<script setup>
import { computed, ref, watch } from "vue";
import { useDragAndDrop } from "@formkit/drag-and-drop/vue";
import { animations } from "@formkit/drag-and-drop";
const props = defineProps({
  modelValue: {
    type: Array,
    default: () => []
  },
  min: {
    type: Number,
    default: 0
  },
  max: {
    type: Number,
    default: Infinity
  },
  sortable: {
    type: Boolean,
    default: true
  },
  addLabel: {
    type: String,
    default: "Add"
  },
  dense: {
    type: Boolean,
    default: false
  },
  bordered: {
    type: Boolean,
    default: true
  },
  separator: {
    type: Boolean,
    default: true
  }
});
const emit = defineEmits(["update:modelValue"]);
const initializeValue = () => {
  let initialValue = props.modelValue ? [...props.modelValue] : [];
  if (initialValue.length < props.min) {
    for (let i = initialValue.length; i < props.min; i++) {
      initialValue.push({});
    }
  }
  if (initialValue.length > props.max) {
    initialValue = initialValue.slice(0, props.max);
  }
  return initialValue;
};
const [parent, localValue] = useDragAndDrop(initializeValue(), {
  dragHandle: ".l-repeater-handle",
  plugins: [animations()]
});
watch(() => props.modelValue, (newVal) => {
  if (JSON.stringify(newVal) !== JSON.stringify(localValue.value)) {
    localValue.value = initializeValue();
  }
}, { deep: true });
watch(localValue, (newVal) => {
  emit("update:modelValue", newVal);
}, { deep: true });
watch(() => props.max, (newVal) => {
  if (localValue.value.length > newVal) {
    localValue.value = localValue.value.slice(0, newVal);
  }
});
watch(() => props.min, (newVal) => {
  if (localValue.value.length < newVal) {
    for (let i = localValue.value.length; i < newVal; i++) {
      localValue.value.push({});
    }
  }
});
const onAdd = () => {
  if (localValue.value.length >= props.max) return;
  localValue.value.push({});
};
const onRemove = (index) => {
  if (localValue.value.length <= props.min) return;
  localValue.value.splice(index, 1);
};
const onMoveUp = (index) => {
  if (index > 0) {
    let temp = localValue.value[index - 1];
    localValue.value[index - 1] = localValue.value[index];
    localValue.value[index] = temp;
  }
};
const onMoveDown = (index) => {
  if (index < localValue.value.length - 1) {
    let temp = localValue.value[index + 1];
    localValue.value[index + 1] = localValue.value[index];
    localValue.value[index] = temp;
  }
};
const isAllowRemove = computed(() => {
  return localValue.value.length > props.min;
});
const isAllowAdd = computed(() => {
  return localValue.value.length < props.max;
});
const isAllowMoveUp = (index) => {
  return index > 0;
};
const isAllowMoveDown = (index) => {
  return index < localValue.value.length - 1;
};
const cursor = ref("cursor-grab");
</script>

<style scoped>
.cursor-grab{cursor:grab}.cursor-grabbing{cursor:grabbing}
</style>

<template>
    <div class="l-repeater">
        <q-list :bordered="bordered" :separator="separator" ref="parent">
            <q-item v-for="(item, index) in localValue" :key="index" :class="{ 'q-pa-xs': !dense, 'q-pa-none': dense }">
                <q-item-section avatar v-if="sortable">
                    <div class="l-repeater-handle" :class="cursor" @mousedown="cursor = 'cursor-grabbing'"
                        @mouseup="cursor = 'cursor-grab'" @mouseleave="cursor = 'cursor-grab'">
                        <q-icon name="sym_o_drag_indicator" size="sm" />
                    </div>
                </q-item-section>

                <q-item-section>
                    <slot :value="localValue[index]" :index="index" :item="item"></slot>
                </q-item-section>

                <q-item-section side>
                    <div class="column q-gutter-xs">
                        <!-- Move up -->
                        <q-btn type="button" @click="onMoveUp(index)" icon="sym_o_arrow_upward" color="primary"
                            :dense="dense" flat :disable="!isAllowMoveUp(index)" size="sm" />

                        <!-- Remove -->
                        <q-btn type="button" @click="onRemove(index)" icon="sym_o_delete" color="negative"
                            :dense="dense" flat :disable="!isAllowRemove" size="sm" />

                        <!-- Move down -->
                        <q-btn type="button" @click="onMoveDown(index)" icon="sym_o_arrow_downward" color="primary"
                            :dense="dense" flat :disable="!isAllowMoveDown(index)" size="sm" />
                    </div>
                </q-item-section>
            </q-item>
        </q-list>

        <q-btn @click="onAdd" :label="addLabel" icon="sym_o_add" color="primary" outline class="q-mt-sm"
            :disable="!isAllowAdd" :dense="dense" />
    </div>
</template>
