<template>
  <div class="space-y-6">
    <section class="space-y-3">
      <div class="flex items-center justify-between">
        <h3 class="text-sm font-semibold">Champs personnalisés du composant</h3>
        <button type="button" class="btn btn-outline btn-xs" @click="addCustomField">
          <IconLucidePlus class="w-3 h-3 mr-2" aria-hidden="true" />
          Ajouter
        </button>
      </div>
      <p v-if="!(localStructure.customFields?.length)" class="text-xs text-gray-500">
        Aucun champ n'a encore été défini.
      </p>
      <div v-else class="space-y-2">
        <div
          v-for="(field, index) in localStructure.customFields"
          :key="`root-field-${index}`"
          class="border border-base-200 rounded-md p-3 space-y-2"
        >
          <div class="flex items-start justify-between gap-2">
            <div class="flex-1 space-y-2">
              <div class="grid grid-cols-1 md:grid-cols-2 gap-2">
                <input
                  v-model="field.name"
                  type="text"
                  class="input input-bordered input-xs"
                  placeholder="Nom du champ"
                />
                <select v-model="field.type" class="select select-bordered select-xs">
                  <option value="text">Texte</option>
                  <option value="number">Nombre</option>
                  <option value="select">Liste</option>
                  <option value="boolean">Oui/Non</option>
                  <option value="date">Date</option>
                </select>
              </div>
              <div class="flex items-center gap-2 text-xs">
                <input v-model="field.required" type="checkbox" class="checkbox checkbox-xs" />
                Obligatoire
              </div>
              <textarea
                v-if="field.type === 'select'"
                v-model="field.optionsText"
                class="textarea textarea-bordered textarea-xs h-20"
                placeholder="Option 1&#10;Option 2"
              ></textarea>
            </div>
            <button type="button" class="btn btn-error btn-xs btn-square" @click="removeCustomField(index)">
              <IconLucideTrash class="w-4 h-4" aria-hidden="true" />
            </button>
          </div>
        </div>
      </div>
    </section>

    <section class="space-y-3">
      <div class="flex items-center justify-between">
        <h3 class="text-sm font-semibold">Pièces incluses par défaut</h3>
        <button type="button" class="btn btn-outline btn-xs" @click="addPiece">
          <IconLucidePlus class="w-3 h-3 mr-2" aria-hidden="true" />
          Ajouter
        </button>
      </div>
      <p v-if="!(localStructure.pieces?.length)" class="text-xs text-gray-500">Aucune pièce définie.</p>
      <div v-else class="space-y-2">
        <div
          v-for="(piece, index) in localStructure.pieces"
          :key="`root-piece-${index}`"
          class="border border-base-200 rounded-md p-3 space-y-3"
        >
          <div class="flex items-start justify-between gap-2">
            <div class="flex-1 space-y-3">
              <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
                <div class="form-control">
                  <label class="label"><span class="label-text">Famille de pièce</span></label>
                  <div>
                    <input
                      :list="`component-piece-type-options-${index}`"
                      v-model="piece.typePieceLabel"
                      type="search"
                      autocomplete="off"
                      class="input input-bordered input-xs"
                      placeholder="Sélectionner une famille"
                      @change="handlePieceTypeChange(piece)"
                      @blur="handlePieceTypeChange(piece)"
                    />
                    <datalist :id="`component-piece-type-options-${index}`">
                      <option
                        v-for="type in availablePieceTypes"
                        :key="type.id"
                        :value="formatPieceTypeOption(type)"
                      />
                    </datalist>
                  </div>
                  <p class="mt-1 text-[11px] text-gray-500">
                    {{ piece.typePieceId ? `Sélection : ${getPieceTypeLabel(piece.typePieceId) || 'Inconnue'}` : 'Aucune famille sélectionnée' }}
                  </p>
                </div>
                <div class="form-control">
                  <label class="label"><span class="label-text">Quantité (optionnel)</span></label>
                  <input
                    v-model.number="piece.quantity"
                    type="number"
                    min="0"
                    step="1"
                    class="input input-bordered input-xs"
                    placeholder="Quantité"
                  />
                </div>
              </div>
            </div>
            <button type="button" class="btn btn-error btn-xs btn-square" @click="removePiece(index)">
              <IconLucideTrash class="w-4 h-4" aria-hidden="true" />
            </button>
          </div>
        </div>
      </div>
    </section>

    <section class="space-y-3">
      <div class="flex items-center justify-between">
        <h3 class="text-sm font-semibold">Sous-composants</h3>
        <button type="button" class="btn btn-outline btn-xs" @click="addSubComponent">
          <IconLucidePlus class="w-3 h-3 mr-2" aria-hidden="true" />
          Ajouter
        </button>
      </div>
      <p v-if="!(localStructure.subComponents?.length)" class="text-xs text-gray-500">
        Aucun sous-composant défini.
      </p>
      <div v-else class="space-y-3">
        <StructureSubComponentEditor
          v-for="(subComponent, index) in localStructure.subComponents"
          :key="`root-sub-${index}`"
          :node="subComponent"
          :depth="0"
          :piece-types="availablePieceTypes"
          :component-types="availableComponentTypes"
          @remove="removeSubComponent(index)"
        />
      </div>
    </section>
  </div>
</template>

<script setup lang="ts">
import { reactive, watch, computed, onMounted } from 'vue'
import IconLucidePlus from '~icons/lucide/plus'
import IconLucideTrash from '~icons/lucide/trash'
import StructureSubComponentEditor from '~/components/StructureSubComponentEditor.vue'
import {
  defaultStructure,
  hydrateStructureForEditor,
  normalizeStructureForSave,
} from '~/shared/modelUtils'
import { usePieceTypes } from '~/composables/usePieceTypes'
import { useComponentTypes } from '~/composables/useComponentTypes'

defineOptions({ name: 'ComponentModelStructureEditor' })

const props = defineProps({
  modelValue: {
    type: Object,
    default: () => defaultStructure(),
  },
})

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

const localStructure = reactive(hydrateStructureForEditor(props.modelValue))

const syncFromProps = (value: any) => {
  const hydrated = hydrateStructureForEditor(value)
  localStructure.customFields = hydrated.customFields
  localStructure.pieces = hydrated.pieces
  localStructure.subComponents = hydrated.subComponents
  lastEmitted = JSON.stringify(normalizeStructureForSave(value))
}

watch(
  () => props.modelValue,
  (value) => {
    syncFromProps(value)
  },
  { deep: true }
)

let lastEmitted = JSON.stringify(normalizeStructureForSave(props.modelValue))

watch(
  localStructure,
  (value) => {
    const normalized = normalizeStructureForSave(value)
    const serialized = JSON.stringify(normalized)
    if (serialized !== lastEmitted) {
      lastEmitted = serialized
      emit('update:modelValue', normalized)
    }
  },
  { deep: true }
)

type ModelTypeOption = {
  id: string
  name: string
  code?: string | null
}

const formatModelTypeOption = (type: ModelTypeOption | undefined | null) => {
  if (!type) return ''
  return type.code ? `${type.name} (${type.code})` : type.name
}

const { pieceTypes, loadPieceTypes } = usePieceTypes()
const { componentTypes, loadComponentTypes } = useComponentTypes()

const availablePieceTypes = computed<ModelTypeOption[]>(() => pieceTypes.value ?? [])
const availableComponentTypes = computed<ModelTypeOption[]>(() => componentTypes.value ?? [])

const pieceTypeMap = computed(() => {
  const map = new Map<string, ModelTypeOption>()
  availablePieceTypes.value.forEach((type) => {
    if (type && typeof type.id === 'string') {
      map.set(type.id, type)
    }
  })
  return map
})

const componentTypeMap = computed(() => {
  const map = new Map<string, ModelTypeOption>()
  availableComponentTypes.value.forEach((type) => {
    if (type && typeof type.id === 'string') {
      map.set(type.id, type)
    }
  })
  return map
})

const formatPieceTypeOption = (type: ModelTypeOption | undefined | null) => formatModelTypeOption(type)
const formatComponentTypeOption = (type: ModelTypeOption | undefined | null) => formatModelTypeOption(type)

const resolvePieceType = (input: string) => {
  const normalized = input.trim().toLowerCase()
  if (!normalized) {
    return null
  }
  return (
    availablePieceTypes.value.find((type) => {
      const formatted = formatPieceTypeOption(type).toLowerCase()
      const name = (type?.name ?? '').toLowerCase()
      const code = (type?.code ?? '').toLowerCase()
      return (
        formatted === normalized
        || name === normalized
        || (!!code && code === normalized)
      )
    }) ?? null
  )
}

const resolveComponentType = (input: string) => {
  const normalized = input.trim().toLowerCase()
  if (!normalized) {
    return null
  }
  return (
    availableComponentTypes.value.find((type) => {
      const formatted = formatComponentTypeOption(type).toLowerCase()
      const name = (type?.name ?? '').toLowerCase()
      const code = (type?.code ?? '').toLowerCase()
      return (
        formatted === normalized
        || name === normalized
        || (!!code && code === normalized)
      )
    }) ?? null
  )
}

const getPieceTypeLabel = (id?: string) => {
  if (!id) return ''
  const option = pieceTypeMap.value.get(id)
  return formatPieceTypeOption(option)
}

const updatePieceTypeLabel = (piece: any) => {
  if (!piece) {
    return
  }
  if (piece.typePieceId) {
    const option = pieceTypeMap.value.get(piece.typePieceId)
    if (option) {
      piece.typePieceLabel = formatPieceTypeOption(option)
      piece.name = option.name || formatPieceTypeOption(option)
    } else if (!piece.typePieceLabel) {
      piece.name = ''
    }
  } else if (piece.typePieceLabel) {
    const match = resolvePieceType(piece.typePieceLabel)
    if (match) {
      piece.typePieceId = match.id
      piece.typePieceLabel = formatPieceTypeOption(match)
      piece.name = match.name || formatPieceTypeOption(match)
    } else {
      piece.typePieceLabel = ''
      piece.name = ''
    }
  }
}

const handlePieceTypeChange = (piece: any) => {
  if (!piece) {
    return
  }
  const value = typeof piece.typePieceLabel === 'string' ? piece.typePieceLabel.trim() : ''
  if (!value) {
    piece.typePieceId = ''
    piece.typePieceLabel = ''
    piece.name = ''
    return
  }
  const match = resolvePieceType(value)
  if (match) {
    piece.typePieceId = match.id
    piece.typePieceLabel = formatPieceTypeOption(match)
    piece.name = match.name || formatPieceTypeOption(match)
  } else {
    piece.typePieceId = ''
    piece.typePieceLabel = ''
    piece.name = ''
  }
}

const applyPieceLabels = (pieces?: any[]) => {
  if (!Array.isArray(pieces)) {
    return
  }
  pieces.forEach((piece) => {
    if (piece?.typePieceId) {
      updatePieceTypeLabel(piece)
    } else if (piece?.typePieceLabel) {
      const match = resolvePieceType(piece.typePieceLabel)
      if (match) {
        piece.typePieceId = match.id
        piece.typePieceLabel = formatPieceTypeOption(match)
        piece.name = match.name || formatPieceTypeOption(match)
      } else {
        piece.typePieceLabel = ''
        piece.name = ''
      }
    } else if (!piece?.name) {
      piece.name = ''
    }
  })
}

const applyComponentTypeLabel = (component: any) => {
  if (!component) {
    return
  }
  if (component.typeComposantId) {
    const option = componentTypeMap.value.get(component.typeComposantId)
    if (option) {
      component.typeComposantLabel = formatComponentTypeOption(option)
      component.name = option.name || formatComponentTypeOption(option)
    } else if (!component.typeComposantLabel) {
      component.name = ''
    }
  } else if (component.typeComposantLabel) {
    const match = resolveComponentType(component.typeComposantLabel)
    if (match) {
      component.typeComposantId = match.id
      component.typeComposantLabel = formatComponentTypeOption(match)
      component.name = match.name || formatComponentTypeOption(match)
    } else {
      component.typeComposantLabel = ''
      component.name = ''
    }
  }
}

const traverseSubComponents = (components?: any[]) => {
  if (!Array.isArray(components)) {
    return
  }
  components.forEach((component) => {
    applyComponentTypeLabel(component)
    applyPieceLabels(component?.pieces)
    traverseSubComponents(component?.subComponents)
  })
}

const syncAllTypeLabels = () => {
  applyPieceLabels(localStructure.pieces)
  traverseSubComponents(localStructure.subComponents)
}

onMounted(async () => {
  const loaders: Promise<any>[] = []
  if (!availablePieceTypes.value.length) {
    loaders.push(loadPieceTypes())
  }
  if (!availableComponentTypes.value.length) {
    loaders.push(loadComponentTypes())
  }
  if (loaders.length) {
    await Promise.all(loaders)
  }
  syncAllTypeLabels()
})

watch(
  () => availablePieceTypes.value,
  () => {
    syncAllTypeLabels()
  },
  { deep: true }
)

watch(
  () => availableComponentTypes.value,
  () => {
    syncAllTypeLabels()
  },
  { deep: true }
)

const ensureArray = (key: 'customFields' | 'pieces' | 'subComponents') => {
  if (!Array.isArray(localStructure[key])) {
    localStructure[key] = []
  }
}

const addCustomField = () => {
  ensureArray('customFields')
  localStructure.customFields.push({
    name: '',
    type: 'text',
    required: false,
    optionsText: '',
    options: [],
  })
}

const removeCustomField = (index: number) => {
  if (!Array.isArray(localStructure.customFields)) return
  localStructure.customFields.splice(index, 1)
}

const addPiece = () => {
  ensureArray('pieces')
  localStructure.pieces.push({
    name: '',
    quantity: undefined,
    typePieceId: '',
    typePieceLabel: '',
  })
}

const removePiece = (index: number) => {
  if (!Array.isArray(localStructure.pieces)) return
  localStructure.pieces.splice(index, 1)
}

const addSubComponent = () => {
  ensureArray('subComponents')
  localStructure.subComponents.push({
    name: '',
    description: '',
    quantity: undefined,
    typeComposantId: '',
    typeComposantLabel: '',
    customFields: [],
    pieces: [],
    subComponents: [],
  })
}

const removeSubComponent = (index: number) => {
  if (!Array.isArray(localStructure.subComponents)) return
  localStructure.subComponents.splice(index, 1)
}
</script>
