<template>
  <div class="card bg-base-100 shadow-lg">
    <div class="card-body space-y-4">
      <div class="flex items-center justify-between">
        <h3 class="card-title text-lg">{{ labels.headerTitle }}</h3>
        <button type="button" class="btn btn-primary btn-sm" @click="addRequirement">
          <IconLucidePlus class="w-4 h-4 mr-2" aria-hidden="true" />
          {{ labels.addButton }}
        </button>
      </div>

      <p class="text-sm text-base-content/50">
        {{ labels.description }}
      </p>

      <div v-if="requirements.length === 0" class="text-sm text-base-content/50 bg-base-200/60 rounded-md p-4">
        {{ labels.emptyState }}
      </div>

      <div
        v-for="(requirement, index) in requirements"
        :key="requirement.id || index"
        class="relative border border-base-200 rounded-lg p-4 pl-12 space-y-3 transition-colors"
        :class="requirementReorderClass(index)"
        @dragenter="onRequirementDragEnter(index)"
        @dragover="onRequirementDragOver"
        @drop="onRequirementDrop(index)"
      >
        <button
          type="button"
          class="absolute left-3 top-4 btn btn-ghost btn-xs btn-square cursor-grab active:cursor-grabbing"
          draggable="true"
          title="Réorganiser"
          @dragstart="onRequirementDragStart(index, $event)"
          @dragend="onRequirementDragEnd"
        >
          <IconLucideGripVertical class="w-4 h-4" aria-hidden="true" />
        </button>
        <div class="flex items-start justify-between gap-3">
          <div class="grid grid-cols-1 md:grid-cols-2 gap-3 flex-1">
            <div class="form-control">
              <label class="label">
                <span class="label-text">{{ labels.typeSelectLabel }}</span>
                <span class="label-text-alt text-error">*</span>
              </label>
              <SearchSelect
                :model-value="normalizeTypeModel(requirement[typeField])"
                :options="typeOptions"
                :loading="typeLoading"
                size="sm"
                :placeholder="labels.typePlaceholder"
                :empty-text="typeOptions.length ? 'Aucun résultat' : 'Aucune option disponible'"
                :option-label="optionLabel"
                :option-description="optionDescription"
                @update:modelValue="(value) => updateRequirement(index, { [typeField]: normalizeTypeValue(value) })"
              />
            </div>

            <div class="form-control">
              <label class="label">
                <span class="label-text">{{ labels.labelFieldLabel }}</span>
                <span v-if="labels.labelFieldHelper" class="label-text-alt text-xs">{{ labels.labelFieldHelper }}</span>
              </label>
              <input
                :value="requirement.label ?? ''"
                type="text"
                class="input input-bordered input-sm"
                :placeholder="labels.labelPlaceholder"
                @input="handleLabelInput(index, $event)"
              />
            </div>

            <div class="form-control">
              <label class="label">
                <span class="label-text">{{ labels.minLabel }}</span>
              </label>
              <input
                :value="requirement.minCount ?? minFallback"
                type="number"
                min="0"
                class="input input-bordered input-sm"
                @input="handleMinInput(index, $event)"
              />
            </div>

            <div class="form-control">
              <label class="label">
                <span class="label-text">{{ labels.maxLabel }}</span>
                <span v-if="labels.maxHelper" class="label-text-alt text-xs">{{ labels.maxHelper }}</span>
              </label>
              <input
                :value="requirement.maxCount ?? ''"
                type="number"
                min="0"
                class="input input-bordered input-sm"
                @input="handleMaxInput(index, $event)"
              />
            </div>
          </div>

          <button
            type="button"
            class="btn btn-square btn-error btn-sm"
            @click="removeRequirement(index)"
          >
            <IconLucideTrash2 class="w-4 h-4" aria-hidden="true" />
          </button>
        </div>

        <div class="flex flex-wrap items-center gap-4 text-sm">
          <label class="flex items-center gap-2">
            <input
              type="checkbox"
              class="checkbox checkbox-sm"
              :checked="(requirement.required ?? requiredFallback) === true"
              @change="handleRequiredChange(index, $event)"
            />
            {{ labels.requiredLabel }}
          </label>

          <label class="flex items-center gap-2">
            <input
              type="checkbox"
              class="checkbox checkbox-sm"
              :checked="(requirement.allowNewModels ?? allowNewModelsFallback) === true"
              @change="handleAllowNewModelsChange(index, $event)"
            />
            {{ labels.allowNewModelsLabel }}
          </label>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'
import type { PropType } from 'vue'
import IconLucidePlus from '~icons/lucide/plus'
import IconLucideTrash2 from '~icons/lucide/trash-2'
import SearchSelect from '~/components/common/SearchSelect.vue'
import IconLucideGripVertical from '~icons/lucide/grip-vertical'

type Option = {
  id: string | number
  name: string
  description?: string | null
}

type Requirement = Record<string, unknown> & {
  id?: string | number
  label?: string
  minCount?: number | null
  maxCount?: number | null
  required?: boolean | null
  allowNewModels?: boolean | null
  orderIndex?: number | null
}

type Labels = {
  headerTitle: string
  addButton: string
  description: string
  emptyState: string
  typeSelectLabel: string
  typePlaceholder: string
  labelFieldLabel: string
  labelFieldHelper?: string
  labelPlaceholder?: string
  minLabel: string
  maxLabel: string
  maxHelper?: string
  requiredLabel: string
  allowNewModelsLabel: string
}

const props = defineProps({
  modelValue: {
    type: Array as PropType<Requirement[]>,
    default: () => [],
  },
  typeOptions: {
    type: Array as PropType<Option[]>,
    default: () => [],
  },
  typeField: {
    type: String,
    required: true,
  },
  labels: {
    type: Object as PropType<Labels>,
    required: true,
  },
  defaultRequirement: {
    type: Function as PropType<() => Requirement>,
    required: true,
  },
  requiredFallback: {
    type: Boolean,
    default: false,
  },
  allowNewModelsFallback: {
    type: Boolean,
    default: true,
  },
  minFallback: {
    type: Number,
    default: 0,
  },
  typeLoading: {
    type: Boolean,
    default: false,
  },
})

const emit = defineEmits(['update:modelValue'])

const requirements = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value),
})

const optionLabel = (option: Option) => {
  if (!option) {
    return ''
  }
  return option.name || ''
}

const optionDescription = (option: Option) => {
  if (!option) {
    return ''
  }
  if (typeof option.description === 'string' && option.description.trim()) {
    return option.description.trim()
  }
  return ''
}

const applyOrderIndex = (list: Requirement[]): Requirement[] =>
  list.map((item, index) => ({
    ...item,
    orderIndex: index,
  }))

const addRequirement = () => {
  requirements.value = applyOrderIndex([
    ...requirements.value,
    props.defaultRequirement(),
  ])
}

const removeRequirement = (index: number) => {
  requirements.value = applyOrderIndex(
    requirements.value.filter((_, i) => i !== index),
  )
}

const updateRequirement = (index: number, patch: Partial<Requirement>) => {
  requirements.value = applyOrderIndex(
    requirements.value.map((item, i) =>
      i === index ? { ...item, ...patch } : item,
    ),
  )
}

const parseNumber = (value: string) => {
  const parsed = Number(value)
  return Number.isFinite(parsed) ? parsed : 0
}

const parseOptionalNumber = (value: string) => {
  if (value === '' || value === null || value === undefined) {
    return null
  }
  const parsed = Number(value)
  return Number.isFinite(parsed) ? parsed : null
}

// Type-safe event handlers
const getInputValue = (event: Event): string => {
  const target = event.target as HTMLInputElement | null
  return target?.value ?? ''
}

const getCheckboxValue = (event: Event): boolean => {
  const target = event.target as HTMLInputElement | null
  return target?.checked ?? false
}

const handleLabelInput = (index: number, event: Event) => {
  updateRequirement(index, { label: getInputValue(event) })
}

const handleMinInput = (index: number, event: Event) => {
  updateRequirement(index, { minCount: parseNumber(getInputValue(event)) })
}

const handleMaxInput = (index: number, event: Event) => {
  updateRequirement(index, { maxCount: parseOptionalNumber(getInputValue(event)) })
}

const handleRequiredChange = (index: number, event: Event) => {
  updateRequirement(index, { required: getCheckboxValue(event) })
}

const handleAllowNewModelsChange = (index: number, event: Event) => {
  updateRequirement(index, { allowNewModels: getCheckboxValue(event) })
}

const draggingRequirementIndex = ref<number | null>(null)
const requirementDropTargetIndex = ref<number | null>(null)

const resetRequirementDragState = () => {
  draggingRequirementIndex.value = null
  requirementDropTargetIndex.value = null
}

const reorderRequirements = (from: number, to: number) => {
  const list = requirements.value
  if (!Array.isArray(list)) {
    resetRequirementDragState()
    return
  }
  if (from === to || from < 0 || to < 0 || from >= list.length || to >= list.length) {
    resetRequirementDragState()
    return
  }
  const updated = list.slice() as Requirement[]
  const [moved] = updated.splice(from, 1)
  if (!moved) {
    resetRequirementDragState()
    return
  }
  updated.splice(to, 0, moved)
  requirements.value = applyOrderIndex(updated)
  resetRequirementDragState()
}

const onRequirementDragStart = (index: number, event: DragEvent) => {
  draggingRequirementIndex.value = index
  requirementDropTargetIndex.value = index
  if (event.dataTransfer) {
    event.dataTransfer.effectAllowed = 'move'
  }
}

const onRequirementDragEnter = (index: number) => {
  if (draggingRequirementIndex.value === null) {
    return
  }
  requirementDropTargetIndex.value = index
}

const onRequirementDragOver = (event: DragEvent) => {
  event.preventDefault()
}

const onRequirementDrop = (index: number) => {
  if (draggingRequirementIndex.value === null) {
    resetRequirementDragState()
    return
  }
  reorderRequirements(draggingRequirementIndex.value, index)
}

const onRequirementDragEnd = () => {
  resetRequirementDragState()
}

const requirementReorderClass = (index: number) => {
  if (draggingRequirementIndex.value === index) {
    return 'border-dashed border-primary'
  }
  if (
    draggingRequirementIndex.value !== null &&
    requirementDropTargetIndex.value === index &&
    draggingRequirementIndex.value !== index
  ) {
    return 'border-primary border-dashed bg-primary/5'
  }
  return ''
}

const normalizeTypeModel = (value: unknown) => {
  if (value === null || value === undefined) {
    return ''
  }
  if (typeof value === 'string' || typeof value === 'number') {
    return value
  }
  return ''
}

const normalizeTypeValue = (value: string | number | null | undefined) => {
  if (value === '' || value === null || value === undefined) {
    return null
  }
  return value
}
</script>

<!--
  Éditeur générique de groupes de contraintes (pièces/composants) pour les types de machine.
  Paramétrer les libellés et la structure via les props pour réutiliser ce bloc.
-->
