<template>
  <form class="space-y-8" @submit.prevent="handleSubmit">
    <section class="space-y-4">
      <div>
        <label class="label" for="model-type-name">
          <span class="label-text">Nom *</span>
        </label>
        <input
          id="model-type-name"
          ref="nameInput"
          v-model.trim="form.name"
          type="text"
          class="input input-bordered w-full"
          name="name"
          minlength="2"
          maxlength="120"
          required
          />
        <p v-if="errors.name" class="mt-1 text-sm text-error">{{ errors.name }}</p>
      </div>
      <div>
        <label class="label" for="model-type-category">
          <span class="label-text">Catégorie *</span>
        </label>
        <select
          id="model-type-category"
          v-model="form.category"
          class="select select-bordered w-full"
          name="category"
          required
          :disabled="lockCategory || isReadonly"
        >
          <option value="COMPONENT">Composants</option>
          <option value="PIECE">Pièces</option>
          <option value="PRODUCT">Produits</option>
        </select>
      </div>

      <div>
        <label class="label" for="model-type-notes">
          <span class="label-text">Notes</span>
        </label>
        <textarea
          id="model-type-notes"
          v-model.trim="form.notes"
          class="textarea textarea-bordered w-full"
          rows="4"
          name="notes"
          maxlength="2000"
        ></textarea>
        <p class="mt-1 text-xs text-base-content/70">Saisissez des informations complémentaires (facultatif).</p>
      </div>
    </section>

    <section class="space-y-4">
      <header>
        <h3 class="text-lg font-semibold text-base-content">Structure du squelette</h3>
        <p class="mt-1 text-sm text-base-content/70">
          Définissez la structure canonique appliquée lors de la création des composants ou pièces de cette catégorie.
        </p>
      </header>

      <div
        v-if="structureLoading"
        class="flex items-center justify-center rounded-lg border border-dashed border-base-300 py-12"
      >
        <span class="loading loading-spinner loading-lg" aria-hidden="true"></span>
        <span class="ml-3 text-sm text-base-content/70">Chargement du squelette…</span>
      </div>

      <template v-else>
        <div
          v-if="form.category === 'COMPONENT'"
          class="space-y-3 rounded-lg border border-base-300 p-4"
        >
          <p class="text-sm text-base-content/70">
            Aperçu :
            <span class="font-medium text-base-content">{{ componentStructurePreview }}</span>
          </p>
          <ComponentModelStructureEditor
            v-model="componentStructure"
            :allow-subcomponents="allowComponentSubcomponents"
            :max-subcomponent-depth="componentSubcomponentMaxDepth"
          />
        </div>

        <div
          v-else-if="form.category === 'PIECE'"
          class="space-y-3 rounded-lg border border-base-300 p-4"
        >
          <p class="text-sm text-base-content/70">
            Aperçu :
            <span class="font-medium text-base-content">{{ pieceStructurePreview }}</span>
          </p>
          <PieceModelStructureEditor v-model="pieceStructure" />
        </div>

        <div
          v-else
          class="space-y-3 rounded-lg border border-base-300 p-4"
        >
          <PieceModelStructureEditor v-model="productStructure" hide-products />
        </div>
      </template>
    </section>

    <ReferenceFormulaBuilder
      v-if="form.category === 'PIECE' || form.category === 'COMPONENT'"
      v-model="form.referenceFormula"
      :custom-fields="formulaBuilderCustomFields"
      :disabled="isReadonly"
    />

    <footer class="flex flex-col gap-3 border-t border-base-300 pt-4 sm:flex-row sm:justify-end">
      <button type="button" class="btn btn-ghost" :disabled="saving" @click="emit('cancel')">
        Annuler
      </button>
      <button v-if="!isReadonly" type="submit" class="btn btn-primary" :disabled="isSubmitDisabled">
        <span v-if="saving" class="loading loading-spinner loading-sm" aria-hidden="true"></span>
        {{ submitLabel }}
      </button>
    </footer>
  </form>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
import ComponentModelStructureEditor from '~/components/ComponentModelStructureEditor.vue'
import PieceModelStructureEditor from '~/components/PieceModelStructureEditor.vue'
import {
  clonePieceStructure,
  cloneProductStructure,
  cloneStructure,
  defaultPieceStructure,
  defaultProductStructure,
  defaultStructure,
  formatPieceStructurePreview,
  formatProductStructurePreview,
  formatStructurePreview,
  normalizePieceStructureForSave,
  normalizeProductStructureForSave,
  normalizeStructureForEditor,
  normalizeStructureForSave,
} from '~/shared/modelUtils'
import type { ModelCategory, ModelTypePayload } from '~/services/modelTypes'

const props = withDefaults(defineProps<{
  mode: 'create' | 'edit'
  initialCategory: ModelCategory
  initialData?: Partial<ModelTypePayload> | null
  saving?: boolean
  lockCategory?: boolean
  structureLoading?: boolean
  allowComponentSubcomponents?: boolean
  componentSubcomponentMaxDepth?: number
  readonly?: boolean
}>(), {
  initialData: null,
  saving: false,
  lockCategory: false,
  structureLoading: false,
  allowComponentSubcomponents: true,
  componentSubcomponentMaxDepth: 1,
  readonly: false,
})

const emit = defineEmits<{
  (e: 'submit', payload: ModelTypePayload): void
  (e: 'cancel'): void
}>()

const lockCategory = computed(() => props.lockCategory ?? false)
const structureLoading = computed(() => props.structureLoading ?? false)
const saving = computed(() => props.saving ?? false)
const allowComponentSubcomponents = computed(() => props.allowComponentSubcomponents !== false)
const componentSubcomponentMaxDepth = computed(() =>
  typeof props.componentSubcomponentMaxDepth === 'number'
    ? props.componentSubcomponentMaxDepth
    : 1,
)
const isReadonly = computed(() => props.readonly === true)

const form = reactive<ModelTypePayload & { referenceFormula?: string | null }>({
  name: '',
  code: '',
  category: props.initialCategory,
  notes: '',
  structure: undefined,
  referenceFormula: null,
})

const formulaBuilderCustomFields = computed(() => {
  let fields: any[] = []
  if (form.category === 'PIECE') {
    const raw = pieceStructure.value?.customFields
    fields = Array.isArray(raw) ? raw : []
  }
  else if (form.category === 'COMPONENT') {
    const raw = componentStructure.value?.customFields
    fields = Array.isArray(raw) ? raw : []
  }
  return fields.filter((f: any) => !f.machineContextOnly)
})

const extractFormulaFields = (formula: string | null | undefined): string[] => {
  if (!formula) return []
  const matches = [...formula.matchAll(/\{([^}]+)\}/gu)]
  return [...new Set(matches.map(m => m[1]).filter((n): n is string => n !== undefined))]
}

const errors = reactive<{ name?: string }>({})
const nameInput = ref<HTMLInputElement | null>(null)

const componentStructure = ref(normalizeStructureForEditor(defaultStructure()))
const pieceStructure = ref(normalizePieceStructureForSave(defaultPieceStructure()))
const productStructure = ref(normalizeProductStructureForSave(defaultProductStructure()))

const generateCodeFromName = (name: string) => {
  const fallback = 'type'
  if (!name) {
    return fallback
  }
  return name
    .normalize('NFD')
    .replace(/[\u0300-\u036F]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '')
    .replace(/-+/g, '-') || fallback
}

const resetStructures = (incomingStructure: ModelTypePayload['structure'], category: ModelCategory) => {
  if (category === 'COMPONENT') {
    componentStructure.value = normalizeStructureForEditor(
      incomingStructure && props.initialData?.category === 'COMPONENT'
        ? incomingStructure
        : defaultStructure(),
    )
    return
  }

  if (category === 'PIECE') {
    pieceStructure.value = normalizePieceStructureForSave(
      incomingStructure && props.initialData?.category === 'PIECE'
        ? incomingStructure
        : defaultPieceStructure(),
    )
    return
  }

  productStructure.value = normalizeProductStructureForSave(
    incomingStructure && props.initialData?.category === 'PRODUCT'
      ? cloneProductStructure(incomingStructure)
      : defaultProductStructure(),
  )
}

const resetForm = () => {
  const incoming = props.initialData ?? {}
  form.name = typeof incoming.name === 'string' ? incoming.name : ''
  form.code = typeof incoming.code === 'string' && incoming.code
    ? incoming.code
    : generateCodeFromName(form.name)
  form.category = incoming.category ?? props.initialCategory
  const incomingRecord = incoming as Record<string, unknown>
  form.notes = typeof incoming.notes === 'string'
    ? incoming.notes
    : typeof incomingRecord.description === 'string'
      ? incomingRecord.description
      : ''

  errors.name = undefined

  const incomingAny = incoming as Record<string, unknown>
  form.referenceFormula = typeof incomingAny.referenceFormula === 'string' ? incomingAny.referenceFormula : null

  resetStructures(incoming.structure, form.category)
}

const submitLabel = computed(() => (props.mode === 'edit' ? 'Enregistrer' : 'Créer'))
const isSubmitDisabled = computed(() => saving.value || structureLoading.value || isReadonly.value)

const validate = () => {
  errors.name = undefined

  const trimmedName = form.name.trim()
  if (trimmedName.length < 2) {
    errors.name = 'Le nom doit contenir au moins 2 caractères.'
  }
  if (trimmedName.length > 120) {
    errors.name = 'Le nom ne peut pas dépasser 120 caractères.'
  }

  return !errors.name
}

const handleSubmit = () => {
  if (isReadonly.value) return
  if (!validate()) {
    return
  }

  const trimmedName = form.name.trim()
  const resolvedCode = form.code?.trim()
    ? form.code.trim()
    : generateCodeFromName(trimmedName)

  const common = {
    name: trimmedName,
    code: resolvedCode,
    notes: form.notes?.trim() ? form.notes.trim() : undefined,
  }

  if (form.category === 'COMPONENT') {
    const formula = form.referenceFormula || null
    const requiredFields = extractFormulaFields(formula)
    emit('submit', {
      ...common,
      category: 'COMPONENT',
      structure: normalizeStructureForSave(cloneStructure(componentStructure.value)),
      referenceFormula: formula,
      requiredFieldsForReference: requiredFields.length ? requiredFields : null,
    } as ModelTypePayload)
    return
  }

  if (form.category === 'PIECE') {
    const formula = form.referenceFormula || null
    const requiredFields = extractFormulaFields(formula)
    emit('submit', {
      ...common,
      category: 'PIECE',
      structure: normalizePieceStructureForSave(clonePieceStructure(pieceStructure.value)),
      referenceFormula: formula,
      requiredFieldsForReference: requiredFields.length ? requiredFields : null,
    } as ModelTypePayload)
    return
  }

  emit('submit', {
    ...common,
    category: 'PRODUCT',
    structure: normalizeProductStructureForSave(cloneProductStructure(productStructure.value)),
  })
}

watch(
  () => props.initialData,
  () => {
    resetForm()
  },
  { deep: true, immediate: true },
)

watch(
  () => form.name,
  (value) => {
    if (props.mode === 'create') {
      form.code = generateCodeFromName(value)
    }
  },
)

watch(
  () => props.initialCategory,
  () => {
    if (!props.initialData) {
      form.category = props.initialCategory
      resetStructures(undefined, form.category)
    }
  },
)

watch(
  () => form.category,
  (category, previous) => {
    if (category === previous) {
      return
    }

    if (category === 'COMPONENT') {
      componentStructure.value = normalizeStructureForEditor(defaultStructure())
    }

    if (category === 'PIECE') {
      pieceStructure.value = normalizePieceStructureForSave(defaultPieceStructure())
    }

    if (category === 'PRODUCT') {
      productStructure.value = normalizeProductStructureForSave(defaultProductStructure())
    }
  },
)

const componentStructurePreview = computed(() => formatStructurePreview(componentStructure.value))
const pieceStructurePreview = computed(() => formatPieceStructurePreview(pieceStructure.value))
const productStructurePreview = computed(() => formatProductStructurePreview(productStructure.value))

onMounted(() => {
  nextTick(() => nameInput.value?.focus())
})
</script>
