<template>
  <main class="container mx-auto px-6 py-8">
    <!-- Loading State -->
    <div v-if="loading" class="flex justify-center items-center py-12">
      <span class="loading loading-spinner loading-lg"></span>
    </div>

    <!-- Machine Details -->
    <div v-else-if="machine" ref="printAreaRef" class="space-y-8">
      <DocumentPreviewModal
        :document="previewDocument"
        :visible="previewVisible"
        @close="closePreview"
      />

      <!-- Header with actions -->
      <div class="flex flex-col gap-4 md:flex-row md:items-start md:justify-between">
        <div class="flex flex-col gap-2">
          <h1 class="text-3xl font-bold">
            {{ machineViewTitle }}
          </h1>
          <div class="btn-group w-full max-w-xs print:hidden" data-print-hide>
            <button
              type="button"
              class="btn btn-sm"
              :class="isDetailsView ? 'btn-primary' : 'btn-outline'"
              @click="changeMachineView('details')"
            >
              Vue machine
            </button>
            <button
              type="button"
              class="btn btn-sm"
              :class="isSkeletonView ? 'btn-primary' : 'btn-outline'"
              :disabled="!machineHasSkeletonRequirements"
              @click="changeMachineView('skeleton')"
            >
              Squelette
            </button>
          </div>
        </div>
        <div class="flex items-center gap-2 print:hidden" data-print-hide>
          <button
            @click="toggleEditMode"
            class="btn btn-primary"
            :class="{ 'btn-outline': isEditMode }"
          >
            <IconLucideSquarePen
              v-if="!isEditMode"
              class="w-5 h-5 mr-2"
              aria-hidden="true"
            />
            <IconLucideEye
              v-else
              class="w-5 h-5 mr-2"
              aria-hidden="true"
            />
            {{ isEditMode ? 'Voir détails' : 'Modifier' }}
          </button>
          <button
            v-if="isDetailsView && !isEditMode"
            @click="openPrintModal"
            type="button"
            class="btn btn-outline btn-secondary"
          >
            <IconLucidePrinter class="w-5 h-5 mr-2" aria-hidden="true" />
            Imprimer
          </button>
        </div>
      </div>

      <template v-if="isDetailsView">
      <!-- Debug info -->
      <div v-if="debug" class="bg-yellow-100 p-4 rounded-lg">
        <p>Debug: Machine trouvée - {{ machine.name }}</p>
        <p>Components count: {{ components.length }}</p>
        <p>Pieces count: {{ pieces.length }}</p>
      </div>
      
      <!-- Hero -->
      <PageHero
        :title="machine.name"
        :subtitle="machine.description || machine.typeMachine?.description"
        min-height="min-h-[20vh]"
        max-width="max-w-md"
        rounded
      >
        <div class="flex justify-center gap-4">
          <div v-if="machine.typeMachine?.category" class="badge badge-outline">
            {{ machine.typeMachine?.category }}
          </div>
          <div v-if="machine.site?.name" class="badge badge-outline">
            {{ machine.site?.name }}
          </div>
          <div v-if="machine.reference" class="badge badge-outline">
            {{ machine.reference }}
          </div>
        </div>
      </PageHero>

      <!-- Machine Info Card -->
      <div class="card bg-base-100 shadow-lg">
        <div class="card-body">
          <h2 class="card-title">Informations de la machine</h2>
          <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
            <div class="form-control">
              <label class="label">
                <span class="label-text">Nom</span>
              </label>
              <input 
                v-if="isEditMode"
                :id="getMachineFieldId('name')"
                v-model="machineName" 
                type="text" 
                class="input input-bordered"
                @blur="updateMachineInfo"
              />
              <div v-else class="input input-bordered bg-base-200">
                {{ machineName }}
              </div>
            </div>
            <div v-if="isEditMode || machineReference" class="form-control">
              <label class="label">
                <span class="label-text">Référence</span>
              </label>
              <input 
                v-if="isEditMode"
                :id="getMachineFieldId('reference')"
                v-model="machineReference" 
                type="text" 
                class="input input-bordered"
                @blur="updateMachineInfo"
              />
              <div v-else class="input input-bordered bg-base-200">
                {{ machineReference }}
              </div>
            </div>
            <div v-if="isEditMode || hasMachineConstructeur" class="form-control">
              <label class="label">
                <span class="label-text">Constructeur</span>
              </label>
              <ConstructeurSelect
                v-if="isEditMode"
                class="w-full"
                :key="machine.value?.id"
                :model-value="machineConstructeurId"
                placeholder="Rechercher un constructeur..."
                @update:modelValue="handleMachineConstructeurChange"
              />
              <div v-else class="input input-bordered bg-base-200">
                <div class="flex flex-col">
                  <span class="font-medium">
                    {{ machineConstructeurDisplay?.name || machineConstructeurContact }}
                  </span>
                  <span v-if="machineConstructeurContact" class="text-xs text-gray-500">
                    {{ machineConstructeurContact }}
                  </span>
                </div>
              </div>
            </div>
          </div>

          <!-- Champs personnalisés -->
          <div v-if="visibleMachineCustomFields.length" class="mt-6 pt-4 border-t border-gray-200">
            <h4 class="font-semibold text-gray-700 mb-3">Champs personnalisés de la machine</h4>
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
              <div
                v-for="field in visibleMachineCustomFields"
                :key="field.customFieldValueId || field.id || field.name"
                class="form-control"
              >
                <label class="label">
                  <span class="label-text text-sm">{{ field.name }}</span>
                  <span v-if="field.required" class="label-text-alt text-error">*</span>
                </label>

                <template v-if="isEditMode">
                  <input
                    v-if="field.type === 'text'"
                    :value="field.value ?? ''"
                    type="text"
                    class="input input-bordered input-sm"
                    :required="field.required"
                    @input="setMachineCustomFieldValue(field, $event.target.value)"
                    @blur="updateMachineCustomField(field)"
                  />
                  <input
                    v-else-if="field.type === 'number'"
                    :value="field.value ?? ''"
                    type="number"
                    class="input input-bordered input-sm"
                    :required="field.required"
                    @input="setMachineCustomFieldValue(field, $event.target.value)"
                    @blur="updateMachineCustomField(field)"
                  />
                  <select
                    v-else-if="field.type === 'select'"
                    :value="field.value ?? ''"
                    class="select select-bordered select-sm"
                    :required="field.required"
                    @change="setMachineCustomFieldValue(field, $event.target.value)"
                    @blur="updateMachineCustomField(field)"
                  >
                    <option value="">Sélectionner...</option>
                    <option
                      v-for="option in field.options"
                      :key="option"
                      :value="option"
                    >
                      {{ option }}
                    </option>
                  </select>
                  <div v-else-if="field.type === 'boolean'" class="flex items-center gap-2">
                    <input
                      :value="field.value ?? ''"
                      type="checkbox"
                      class="checkbox checkbox-sm"
                      :checked="String(field.value).toLowerCase() === 'true'"
                      @change="setMachineCustomFieldValue(field, $event.target.checked ? 'true' : 'false')"
                      @blur="updateMachineCustomField(field)"
                    />
                    <span class="text-sm">{{ String(field.value).toLowerCase() === 'true' ? 'Oui' : 'Non' }}</span>
                  </div>
                  <input
                    v-else-if="field.type === 'date'"
                    :value="field.value ?? ''"
                    type="date"
                    class="input input-bordered input-sm"
                    :required="field.required"
                    @input="setMachineCustomFieldValue(field, $event.target.value)"
                    @blur="updateMachineCustomField(field)"
                  />
                  <div v-else class="text-xs text-error">
                    Type de champ non pris en charge
                  </div>
                </template>
                <template v-else>
                  <div class="input input-bordered input-sm bg-base-200">
                    {{ formatCustomFieldValue(field) }}
                  </div>
                </template>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Documents -->
      <div class="card bg-base-100 shadow-lg mt-6">
        <div class="card-body space-y-4">
          <div class="flex items-center justify-between">
            <div>
              <h2 class="card-title">Documents de la machine</h2>
              <p class="text-xs text-gray-500">Ajoutez ou consultez les documents liés à cette machine.</p>
            </div>
            <span v-if="isEditMode && machineDocumentFiles.length" class="badge badge-outline">
              {{ machineDocumentFiles.length }} fichier{{ machineDocumentFiles.length > 1 ? 's' : '' }} sélectionné{{ machineDocumentFiles.length > 1 ? 's' : '' }}
            </span>
          </div>

          <DocumentUpload
            v-if="isEditMode"
            v-model="machineDocumentFiles"
            title="Déposer des fichiers pour la machine"
            subtitle="Formats acceptés : PDF, images, documents..."
            @files-added="handleMachineFilesAdded"
          />

          <div v-if="machineDocumentsList.length" class="space-y-2">
            <div
              v-for="document in machineDocumentsList"
              :key="document.id"
              class="flex items-center justify-between rounded border border-base-200 bg-base-100 px-3 py-2"
            >
              <div class="flex items-center gap-3 text-sm">
                <div
                  class="flex-shrink-0 overflow-hidden rounded-md border border-base-200 bg-base-200/70 flex items-center justify-center"
                  :class="documentThumbnailClass(document)"
                >
                  <img
                    v-if="isImageDocument(document) && document.path"
                    :src="document.path"
                    class="h-full w-full object-cover"
                    :alt="`Aperçu de ${document.name}`"
                  >
                  <iframe
                    v-else-if="shouldInlinePdf(document)"
                    :src="documentPreviewSrc(document)"
                    class="h-full w-full border-0 bg-white"
                    title="Aperçu PDF"
                  />
                  <component
                    v-else
                    :is="documentIcon(document).component"
                    class="h-6 w-6"
                    :class="documentIcon(document).colorClass"
                    aria-hidden="true"
                  />
                </div>
                <div>
                  <div class="font-medium">{{ document.name }}</div>
                  <div class="text-xs text-gray-500">
                    {{ document.mimeType || 'Inconnu' }} • {{ formatSize(document.size) }}
                  </div>
                </div>
              </div>
              <div class="flex items-center gap-2">
                <button
                  type="button"
                  class="btn btn-ghost btn-xs"
                  :disabled="!canPreviewDocument(document)"
                  :title="canPreviewDocument(document) ? 'Consulter le document' : 'Aucun aperçu disponible pour ce type'"
                  @click="openPreview(document)"
                >
                  Consulter
                </button>
                <button type="button" class="btn btn-ghost btn-xs" @click="downloadDocument(document)">
                  Télécharger
                </button>
                <button
                  v-if="isEditMode"
                  type="button"
                  class="btn btn-error btn-xs"
                  :disabled="machineDocumentsUploading"
                  @click="removeMachineDocument(document.id)"
                >
                  Supprimer
                </button>
              </div>
            </div>
          </div>
          <p v-else class="text-xs text-gray-500">Aucun document lié à cette machine.</p>
        </div>
      </div>

      <!-- Components Section -->
      <div class="card bg-base-100 shadow-lg">
        <div class="card-body">
          <div class="flex justify-between items-center mb-4">
            <h2 class="card-title">Composants</h2>
            <button 
              type="button"
              class="btn btn-ghost btn-sm gap-2"
              @click="toggleAllComponents"
              :title="componentsCollapsed ? 'Déplier tous les composants' : 'Replier tous les composants'"
            >
              <IconLucideChevronRight
                class="w-5 h-5 transition-transform"
                :class="componentsCollapsed ? 'rotate-0' : 'rotate-90'"
                aria-hidden="true"
              />
              <span class="text-sm">
                {{ componentsCollapsed ? 'Tout déplier' : 'Tout replier' }}
              </span>
            </button>
          </div>

          <ComponentHierarchy
            :components="components"
            :is-edit-mode="isEditMode"
            :collapse-all="componentsCollapsed"
            :toggle-token="collapseToggleToken"
            @update="updateComponent"
            @edit-piece="updatePieceFromComponent"
            @custom-field-update="updatePieceCustomField"
          />
        </div>
      </div>

      <!-- Machine Pieces Section -->
      <div class="card bg-base-100 shadow-lg">
        <div class="card-body">
          <div class="flex justify-between items-center mb-4">
            <h2 class="card-title">Pièces de la machine</h2>
          </div>

          <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
            <PieceItem
              v-for="piece in machinePieces"
              :key="piece.id"
              :piece="piece"
              :is-edit-mode="isEditMode"
              @update="updatePieceInfo"
              @edit="editPiece"
              @custom-field-update="updatePieceCustomField"
            />
          </div>
        </div>
      </div>
    </template>

    <template v-else>
      <div
        v-if="componentRequirementGroups.length || pieceRequirementGroups.length"
        class="card bg-base-100 shadow-lg"
      >
        <div class="card-body space-y-6">
          <div>
            <h2 class="card-title">Structure sélectionnée</h2>
            <p class="text-sm text-gray-500">
              Synthèse des familles définies dans le type et des modèles utilisés pour cette machine.
            </p>
          </div>

          <div v-if="componentRequirementGroups.length" class="space-y-4">
            <h3 class="text-sm font-semibold text-gray-700">Composants</h3>
            <div
              v-for="group in componentRequirementGroups"
              :key="group.requirement.id"
              class="rounded-lg border border-base-200 p-4"
            >
              <div class="flex flex-wrap items-center justify-between gap-2 mb-3">
                <div>
                  <h4 class="font-medium text-sm">
                    {{ group.requirement.label || group.requirement.typeComposant?.name || 'Famille de composants' }}
                  </h4>
                  <p class="text-xs text-gray-500">
                    Type : {{ group.requirement.typeComposant?.name || 'Non défini' }} · Min {{ group.requirement.minCount ?? (group.requirement.required ? 1 : 0) }} · Max {{ group.requirement.maxCount ?? '∞' }}
                  </p>
                </div>
                <span class="badge badge-outline badge-sm">{{ group.components.length }} composant(s)</span>
              </div>

              <div v-if="group.components.length" class="space-y-2">
                <div
                  v-for="component in group.components"
                  :key="component.id"
                  class="flex flex-wrap items-center gap-2 text-sm"
                >
                  <span class="font-medium">{{ component.name }}</span>
                  <span v-if="component.parentComposantId" class="text-xs text-gray-500">
                    (Sous-composant)
                  </span>
                  <div
                    v-if="summarizeCustomFields(component.customFields || []).length"
                    class="w-full flex flex-wrap gap-2 text-xs text-gray-600"
                  >
                    <span
                      v-for="field in summarizeCustomFields(component.customFields || [])"
                      :key="field.key"
                      class="badge badge-ghost badge-sm whitespace-pre-wrap"
                    >
                      <span class="font-medium">{{ field.label }} :</span>
                      <span class="ml-1">{{ field.value }}</span>
                    </span>
                  </div>
                </div>
              </div>
              <p v-else class="text-xs text-gray-500">Aucun composant rattaché à ce groupe.</p>
            </div>
          </div>

          <div v-if="pieceRequirementGroups.length" class="space-y-4">
            <h3 class="text-sm font-semibold text-gray-700">Pièces principales</h3>
            <div
              v-for="group in pieceRequirementGroups"
              :key="group.requirement.id"
              class="rounded-lg border border-base-200 p-4"
            >
              <div class="flex flex-wrap items-center justify-between gap-2 mb-3">
                <div>
                  <h4 class="font-medium text-sm">
                    {{ group.requirement.label || group.requirement.typePiece?.name || 'Groupe de pièces' }}
                  </h4>
                  <p class="text-xs text-gray-500">
                    Type : {{ group.requirement.typePiece?.name || 'Non défini' }} · Min {{ group.requirement.minCount ?? (group.requirement.required ? 1 : 0) }} · Max {{ group.requirement.maxCount ?? '∞' }}
                  </p>
                </div>
                <span class="badge badge-outline badge-sm">{{ group.pieces.length }} pièce(s)</span>
              </div>

              <div v-if="group.pieces.length" class="space-y-2">
                <div
                  v-for="piece in group.pieces"
                  :key="piece.id"
                  class="flex flex-wrap items-center gap-2 text-sm"
                >
                  <span class="font-medium">{{ piece.name }}</span>
                  <span v-if="piece.parentComponentName" class="text-xs text-gray-500">
                    (Rattachée à {{ piece.parentComponentName }})
                  </span>
                  <div
                    v-if="summarizeCustomFields(piece.customFields || []).length"
                    class="w-full flex flex-wrap gap-2 text-xs text-gray-600"
                  >
                    <span
                      v-for="field in summarizeCustomFields(piece.customFields || [])"
                      :key="field.key"
                      class="badge badge-ghost badge-sm whitespace-pre-wrap"
                    >
                      <span class="font-medium">{{ field.label }} :</span>
                      <span class="ml-1">{{ field.value }}</span>
                    </span>
                  </div>
                </div>
              </div>
              <p v-else class="text-xs text-gray-500">Aucune pièce rattachée à ce groupe.</p>
            </div>
          </div>
        </div>
      </div>
    </template>
  </div>

    <!-- Error State -->
    <div v-else class="text-center py-12">
      <div class="max-w-md mx-auto">
        <IconLucideAlertTriangle class="w-16 h-16 mx-auto text-gray-400 mb-4" aria-hidden="true" />
        <h3 class="text-lg font-medium text-gray-900 mb-2">Machine non trouvée</h3>
        <p class="text-gray-500 mb-4">La machine avec l'ID "{{ machineId }}" n'existe pas ou a été supprimée.</p>
        <NuxtLink to="/machines" class="btn btn-primary">
          Retour aux machines
        </NuxtLink>
      </div>
    </div>
  </main>

  <MachinePrintSelectionModal
    :open="printModalOpen"
    :selection="printSelection"
    :components="components"
    :pieces="machinePieces"
    @close="closePrintModal"
    @confirm="handlePrintConfirm"
    @select-all="setAllPrintSelection(true)"
    @deselect-all="setAllPrintSelection(false)"
  />

</template>

<script setup>
import { ref, reactive, onMounted, computed, watch, nextTick } from 'vue'
import { useRoute } from 'vue-router'
import { useMachines } from '~/composables/useMachines'
import { useComposants } from '~/composables/useComposants'
import { usePieces } from '~/composables/usePieces'
import { useComponentTypes } from '~/composables/useComponentTypes'
import { usePieceTypes } from '~/composables/usePieceTypes'
import { useCustomFields } from '~/composables/useCustomFields'
import { useApi } from '~/composables/useApi'
import { useToast } from '~/composables/useToast'
import { useDocuments } from '~/composables/useDocuments'
import { getFileIcon } from '~/utils/fileIcons'
import { sanitizeDefinitionOverrides, normalizeStructureForEditor } from '~/shared/modelUtils'
import { canPreviewDocument, isImageDocument, isPdfDocument } from '~/utils/documentPreview'
import ComponentHierarchy from '~/components/ComponentHierarchy.vue'
import DocumentUpload from '~/components/DocumentUpload.vue'
import ConstructeurSelect from '~/components/ConstructeurSelect.vue'
import { useConstructeurs } from '~/composables/useConstructeurs'
import DocumentPreviewModal from '~/components/DocumentPreviewModal.vue'
import PageHero from '~/components/PageHero.vue'
import MachinePrintSelectionModal from '~/components/MachinePrintSelectionModal.vue'
import { buildMachinePrintContext, buildMachinePrintHtml } from '~/utils/printTemplates/machineReport'
import IconLucideAlertTriangle from '~icons/lucide/alert-triangle'
import IconLucideSquarePen from '~icons/lucide/square-pen'
import IconLucideEye from '~icons/lucide/eye'
import IconLucideChevronRight from '~icons/lucide/chevron-right'
import IconLucidePrinter from '~icons/lucide/printer'
import IconLucidePlus from '~icons/lucide/plus'
import IconLucideX from '~icons/lucide/x'

const route = useRoute()
const machineId = route.params.id

// Vérifier que l'ID est valide
if (!machineId) {
  console.error('ID de machine manquant')
}

// Composables
const {
  updateMachine: updateMachineApi,
  reconfigureSkeleton: reconfigureMachineSkeleton,
} = useMachines()
const {
  updateComposant: updateComposantApi
} = useComposants()
const {
  updatePiece: updatePieceApi
} = usePieces()
const { componentTypes, loadComponentTypes } = useComponentTypes()
const { pieceTypes, loadPieceTypes } = usePieceTypes()

const { upsertCustomFieldValue, updateCustomFieldValue: updateCustomFieldValueApi } = useCustomFields()
const { get } = useApi()
const {
  uploadDocuments,
  deleteDocument,
  loadDocumentsByMachine,
  loadDocumentsByComponent,
  loadDocumentsByPiece
} = useDocuments()
const toast = useToast()

// Data
const loading = ref(true)
const machine = ref(null)
const components = ref([])
const pieces = ref([])
const machineComponentLinks = ref([])
const machinePieceLinks = ref([])
const printAreaRef = ref(null)

const { constructeurs, loadConstructeurs } = useConstructeurs()

// Champs de la machine
const machineName = ref('')
const machineReference = ref('')
const machineConstructeurId = ref(null)
const machineConstructeurDisplay = computed(() => {
  const id = machineConstructeurId.value || machine.value?.constructeur?.id || machine.value?.constructeurId
  if (!id) return machine.value?.constructeur || null
  return constructeurs.value.find(item => item.id === id) || machine.value?.constructeur || null
})
const machineConstructeurContact = computed(() => {
  const constructeur = machineConstructeurDisplay.value
  if (!constructeur) {
    return ''
  }
  return [constructeur.email, constructeur.phone].filter(Boolean).join(' • ')
})
const hasMachineConstructeur = computed(() => {
  const constructeur = machineConstructeurDisplay.value
  if (!constructeur) {
    return false
  }
  return Boolean(constructeur.name || machineConstructeurContact.value)
})

const machineDocumentFiles = ref([])
const machineDocumentsUploading = ref(false)
const machineDocumentsLoaded = ref(false)
const machineCustomFields = ref([])
const previewDocument = ref(null)
const previewVisible = ref(false)
const printModalOpen = ref(false)
const printSelection = reactive({
  machine: {
    info: true,
    customFields: true,
    documents: true,
  },
  components: {},
  pieces: {},
})

const activeMachineView = ref('details')
const isDetailsView = computed(() => activeMachineView.value === 'details')
const isSkeletonView = computed(() => activeMachineView.value === 'skeleton')

const skeletonEditor = reactive({
  open: false,
  loading: false,
  submitting: false,
})

const componentRequirementSelections = reactive({})
const pieceRequirementSelections = reactive({})

const machineType = computed(() => machine.value?.typeMachine || null)
const componentRequirements = computed(() => machineType.value?.componentRequirements || [])
const pieceRequirements = computed(() => machineType.value?.pieceRequirements || [])
const machineHasSkeletonRequirements = computed(() =>
  componentRequirements.value.length > 0 || pieceRequirements.value.length > 0
)

const componentTypeOptions = computed(() => componentTypes.value || [])
const pieceTypeOptions = computed(() => pieceTypes.value || [])

const componentTypeLabelMap = computed(() => {
  const map = new Map()
  componentTypeOptions.value.forEach((type) => {
    if (type?.id) {
      map.set(type.id, type.name || '')
    }
  })
  componentRequirements.value.forEach((requirement) => {
    const type = requirement.typeComposant
    if (type?.id) {
      map.set(type.id, type.name || '')
    }
  })
  return map
})

const pieceTypeLabelMap = computed(() => {
  const map = new Map()
  pieceTypeOptions.value.forEach((type) => {
    if (type?.id) {
      map.set(type.id, type.name || '')
    }
  })
  pieceRequirements.value.forEach((requirement) => {
    const type = requirement.typePiece
    if (type?.id) {
      map.set(type.id, type.name || '')
    }
  })
  return map
})

const isPlainObject = (value) => Object.prototype.toString.call(value) === '[object Object]'

const resolveIdentifier = (...candidates) => {
  for (const candidate of candidates) {
    if (candidate !== undefined && candidate !== null && candidate !== '') {
      return candidate
    }
  }
  return null
}

const extractParentLinkIdentifiers = (source) => {
  if (!source || typeof source !== 'object') {
    return {}
  }

  const identifiers = {}

  const idKeys = [
    'parentRequirementId',
    'parentComponentRequirementId',
    'parentPieceRequirementId',
    'parentMachineComponentRequirementId',
    'parentMachinePieceRequirementId',
    'parentLinkId',
    'parentComponentLinkId',
    'parentPieceLinkId',
    'parentComponentId',
    'parentPieceId',
  ]

  idKeys.forEach((key) => {
    if (Object.prototype.hasOwnProperty.call(source, key)) {
      const value = source[key]
      if (value !== undefined && value !== null && value !== '') {
        identifiers[key] = value
      }
    }
  })

  const objectKeys = [
    'parentRequirement',
    'parentComponentRequirement',
    'parentPieceRequirement',
    'parentMachineComponentRequirement',
    'parentMachinePieceRequirement',
  ]

  objectKeys.forEach((key) => {
    const value = source[key]
    if (isPlainObject(value) && value.id !== undefined && value.id !== null && value.id !== '') {
      const idKey = `${key}Id`
      if (!Object.prototype.hasOwnProperty.call(identifiers, idKey)) {
        identifiers[idKey] = value.id
      }
    }
  })

  return identifiers
}

const resolveComponentRequirementTypeLabel = (requirement, entry) => {
  const typeId = entry?.typeComposantId || requirement?.typeComposantId || null
  if (!typeId) {
    return requirement?.typeComposant?.name || 'Type non défini'
  }
  return componentTypeLabelMap.value.get(typeId) || requirement?.typeComposant?.name || 'Type non défini'
}

const resolvePieceRequirementTypeLabel = (requirement, entry) => {
  const typeId = entry?.typePieceId || requirement?.typePieceId || null
  if (!typeId) {
    return requirement?.typePiece?.name || 'Type non défini'
  }
  return pieceTypeLabelMap.value.get(typeId) || requirement?.typePiece?.name || 'Type non défini'
}

const getComponentRequirementEntries = (requirementId) => {
  return componentRequirementSelections[requirementId] || []
}

const getPieceRequirementEntries = (requirementId) => {
  return pieceRequirementSelections[requirementId] || []
}

const createComponentSelectionEntry = (requirement, source = null) => {
  const link = source?.machineComponentLink || null

  const entry = {
    linkId: resolveIdentifier(link?.id, source?.machineComponentLinkId, source?.linkId),
    composantId: resolveIdentifier(source?.composantId, source?.componentId, source?.id),
    parentLinkId: resolveIdentifier(
      link?.parentLinkId,
      link?.parentComponentLinkId,
      source?.parentComponentLinkId,
      source?.parentLinkId,
    ),
    parentRequirementId: resolveIdentifier(
      link?.parentRequirementId,
      source?.parentRequirementId,
      requirement?.parentRequirementId,
    ),
    parentMachineComponentRequirementId: resolveIdentifier(
      link?.parentMachineComponentRequirementId,
      source?.parentMachineComponentRequirementId,
      requirement?.parentMachineComponentRequirementId,
    ),
    parentMachinePieceRequirementId: resolveIdentifier(
      link?.parentMachinePieceRequirementId,
      source?.parentMachinePieceRequirementId,
      requirement?.parentMachinePieceRequirementId,
    ),
    parentComponentId: resolveIdentifier(link?.parentComponentId, source?.parentComponentId),
    parentPieceId: resolveIdentifier(link?.parentPieceId, source?.parentPieceId),
    typeComposantId:
      source?.typeMachineComponentRequirement?.typeComposantId
      || source?.typeComposantId
      || source?.typeComposant?.id
      || requirement?.typeComposantId
      || null,
    definition: {
      name:
        source?.name
        || source?.nom
        || requirement?.typeComposant?.name
        || '',
      reference: source?.reference || '',
      constructeurId: source?.constructeurId || source?.constructeur?.id || null,
      prix:
        source?.prix
        ?? source?.price
        ?? null,
    },
  }

  if (link?.overrides && isPlainObject(link.overrides)) {
    entry.definition = {
      ...entry.definition,
      ...link.overrides,
    }
  }

  return entry
}

const createPieceSelectionEntry = (requirement, source = null) => {
  const link = source?.machinePieceLink || null

  const entry = {
    linkId: resolveIdentifier(link?.id, source?.machinePieceLinkId, source?.linkId),
    pieceId: resolveIdentifier(source?.pieceId, source?.id),
    parentLinkId: resolveIdentifier(link?.parentLinkId, source?.parentLinkId),
    parentComponentLinkId: resolveIdentifier(
      link?.parentComponentLinkId,
      source?.parentComponentLinkId,
      source?.machineComponentLinkId,
    ),
    parentRequirementId: resolveIdentifier(
      link?.parentRequirementId,
      source?.parentRequirementId,
      requirement?.parentRequirementId,
    ),
    parentMachineComponentRequirementId: resolveIdentifier(
      link?.parentMachineComponentRequirementId,
      source?.parentMachineComponentRequirementId,
      requirement?.parentMachineComponentRequirementId,
    ),
    parentMachinePieceRequirementId: resolveIdentifier(
      link?.parentMachinePieceRequirementId,
      source?.parentMachinePieceRequirementId,
      requirement?.parentMachinePieceRequirementId,
    ),
    parentComponentId: resolveIdentifier(link?.parentComponentId, source?.parentComponentId, source?.composantId),
    parentPieceId: resolveIdentifier(link?.parentPieceId, source?.parentPieceId),
    composantId: resolveIdentifier(source?.composantId, link?.composantId, link?.componentId),
    typePieceId:
      source?.typeMachinePieceRequirement?.typePieceId
      || source?.typePieceId
      || source?.typePiece?.id
      || requirement?.typePieceId
      || null,
    definition: {
      name:
        source?.name
        || source?.nom
        || requirement?.typePiece?.name
        || '',
      reference: source?.reference || '',
      constructeurId: source?.constructeurId || source?.constructeur?.id || null,
      prix:
        source?.prix
        ?? source?.price
        ?? null,
    },
  }

  if (link?.overrides && isPlainObject(link.overrides)) {
    entry.definition = {
      ...entry.definition,
      ...link.overrides,
    }
  }

  return entry
}

const resetSkeletonRequirementSelections = () => {
  Object.keys(componentRequirementSelections).forEach((key) => {
    delete componentRequirementSelections[key]
  })
  Object.keys(pieceRequirementSelections).forEach((key) => {
    delete pieceRequirementSelections[key]
  })
}

const addComponentSelectionEntry = (requirement) => {
  const entries = getComponentRequirementEntries(requirement.id)
  const max = requirement.maxCount ?? null
  if (max !== null && entries.length >= max) {
    toast.showError(
      `Vous ne pouvez pas ajouter plus de ${max} composant(s) pour ${requirement.label || requirement.typeComposant?.name || 'ce groupe'}`
    )
    return
  }
  componentRequirementSelections[requirement.id] = [
    ...entries,
    createComponentSelectionEntry(requirement),
  ]
}

const removeComponentSelectionEntry = (requirementId, index) => {
  const entries = getComponentRequirementEntries(requirementId)
  componentRequirementSelections[requirementId] = entries.filter((_, i) => i !== index)
}

const setComponentRequirementType = (requirementId, index, value) => {
  const entries = getComponentRequirementEntries(requirementId)
  const entry = entries[index]
  if (!entry) return
  entry.typeComposantId = value || null
}

const setComponentRequirementConstructeur = (requirementId, index, value) => {
  const entries = getComponentRequirementEntries(requirementId)
  const entry = entries[index]
  if (!entry) return
  entry.definition.constructeurId = value || null
}

const addPieceSelectionEntry = (requirement) => {
  const entries = getPieceRequirementEntries(requirement.id)
  const max = requirement.maxCount ?? null
  if (max !== null && entries.length >= max) {
    toast.showError(
      `Vous ne pouvez pas ajouter plus de ${max} pièce(s) pour ${requirement.label || requirement.typePiece?.name || 'ce groupe'}`
    )
    return
  }
  pieceRequirementSelections[requirement.id] = [...entries, createPieceSelectionEntry(requirement)]
}

const removePieceSelectionEntry = (requirementId, index) => {
  const entries = getPieceRequirementEntries(requirementId)
  pieceRequirementSelections[requirementId] = entries.filter((_, i) => i !== index)
}

const setPieceRequirementType = (requirementId, index, value) => {
  const entries = getPieceRequirementEntries(requirementId)
  const entry = entries[index]
  if (!entry) return
  entry.typePieceId = value || null
}

const setPieceRequirementConstructeur = (requirementId, index, value) => {
  const entries = getPieceRequirementEntries(requirementId)
  const entry = entries[index]
  if (!entry) return
  entry.definition.constructeurId = value || null
}

const collectPiecesForSkeleton = () => {
  const aggregated = []
  machinePieces.value.forEach((piece) => {
    aggregated.push(piece)
  })
  flattenedComponents.value.forEach((component) => {
    ;(component.pieces || []).forEach((piece) => {
      aggregated.push(piece)
    })
  })
  return aggregated
}

const initializeSkeletonRequirementSelections = async () => {
  skeletonEditor.loading = true
  try {
    resetSkeletonRequirementSelections()
    const type = machineType.value
    if (!type) {
      return
    }

    ;(type.componentRequirements || []).forEach((requirement) => {
      const existingComponents = flattenedComponents.value.filter(
        (component) => component.typeMachineComponentRequirementId === requirement.id,
      )
      const entries = existingComponents.map((component) =>
        createComponentSelectionEntry(requirement, component),
      )

      const min = requirement.minCount ?? (requirement.required ? 1 : 0)
      while (entries.length < min) {
        entries.push(createComponentSelectionEntry(requirement))
      }

      if (entries.length) {
        componentRequirementSelections[requirement.id] = entries
      }
    })

    const allPieces = collectPiecesForSkeleton()
    ;(type.pieceRequirements || []).forEach((requirement) => {
      const existingPieces = allPieces.filter(
        (piece) => piece.typeMachinePieceRequirementId === requirement.id,
      )
      const entries = existingPieces.map((piece) =>
        createPieceSelectionEntry(requirement, piece),
      )

      const min = requirement.minCount ?? (requirement.required ? 1 : 0)
      while (entries.length < min) {
        entries.push(createPieceSelectionEntry(requirement))
      }

      if (entries.length) {
        pieceRequirementSelections[requirement.id] = entries
      }
    })
  } finally {
    skeletonEditor.loading = false
  }
}

const openSkeletonEditor = async () => {
  if (skeletonEditor.open) {
    return
  }
  skeletonEditor.open = true
  await initializeSkeletonRequirementSelections()
}

const closeSkeletonEditor = () => {
  if (!skeletonEditor.open) {
    return
  }
  if (skeletonEditor.submitting) {
    return
  }
  skeletonEditor.open = false
  skeletonEditor.loading = false
  skeletonEditor.submitting = false
  resetSkeletonRequirementSelections()
}

const changeMachineView = async (view) => {
  if (view === activeMachineView.value) {
    return
  }

  if (view === 'skeleton') {
    if (!machineHasSkeletonRequirements.value) {
      toast.showInfo('Aucun squelette configuré pour cette machine.')
      return
    }

    activeMachineView.value = 'skeleton'

    if (!skeletonEditor.open) {
      try {
        await openSkeletonEditor()
      } catch (error) {
        console.error('Impossible d\'ouvrir l\'éditeur de squelette:', error)
        toast.showError('Impossible de charger les éléments du squelette.')
        activeMachineView.value = 'details'
      }
    }
    return
  }

  closeSkeletonEditor()
  activeMachineView.value = 'details'
}

const validateSkeletonSelections = (type) => {
  const errors = []
  const componentLinksPayload = []
  const pieceLinksPayload = []

  for (const requirement of type.componentRequirements || []) {
    const entries = getComponentRequirementEntries(requirement.id)
    const min = requirement.minCount ?? (requirement.required ? 1 : 0)
    const max = requirement.maxCount ?? null

    if (entries.length < min) {
      errors.push(
        `Le groupe "${requirement.label || requirement.typeComposant?.name || 'Composants'}" nécessite au moins ${min} élément(s).`,
      )
    }

    if (max !== null && entries.length > max) {
      errors.push(
        `Le groupe "${requirement.label || requirement.typeComposant?.name || 'Composants'}" ne peut dépasser ${max} élément(s).`,
      )
    }

    entries.forEach((entry) => {
      const resolvedTypeId = entry.typeComposantId || requirement.typeComposantId || null
      if (!resolvedTypeId) {
        errors.push(
          `Le groupe "${requirement.label || requirement.typeComposant?.name || 'Composants'}" nécessite un type de composant.`,
        )
        return
      }

      const payload = {
        requirementId: requirement.id,
        typeComposantId: resolvedTypeId,
      }

      if (entry.linkId) {
        payload.id = entry.linkId
        payload.linkId = entry.linkId
      }

      if (entry.composantId) {
        payload.composantId = entry.composantId
      }

      const overrides = sanitizeDefinitionOverrides(entry.definition)
      if (overrides) {
        payload.overrides = overrides
      }

      Object.assign(
        payload,
        extractParentLinkIdentifiers(requirement),
        extractParentLinkIdentifiers(entry),
      )

      componentLinksPayload.push(payload)
    })
  }

  for (const requirement of type.pieceRequirements || []) {
    const entries = getPieceRequirementEntries(requirement.id)
    const min = requirement.minCount ?? (requirement.required ? 1 : 0)
    const max = requirement.maxCount ?? null

    if (entries.length < min) {
      errors.push(
        `Le groupe "${requirement.label || requirement.typePiece?.name || 'Pièces'}" nécessite au moins ${min} élément(s).`,
      )
    }

    if (max !== null && entries.length > max) {
      errors.push(
        `Le groupe "${requirement.label || requirement.typePiece?.name || 'Pièces'}" ne peut dépasser ${max} élément(s).`,
      )
    }

    entries.forEach((entry) => {
      const resolvedTypeId = entry.typePieceId || requirement.typePieceId || null
      if (!resolvedTypeId) {
        errors.push(
          `Le groupe "${requirement.label || requirement.typePiece?.name || 'Pièces'}" nécessite un type de pièce.`,
        )
        return
      }

      const payload = {
        requirementId: requirement.id,
        typePieceId: resolvedTypeId,
      }

      if (entry.linkId) {
        payload.id = entry.linkId
        payload.linkId = entry.linkId
      }

      if (entry.pieceId) {
        payload.pieceId = entry.pieceId
      }

      if (entry.composantId) {
        payload.composantId = entry.composantId
      }

      const overrides = sanitizeDefinitionOverrides(entry.definition)
      if (overrides) {
        payload.overrides = overrides
      }

      Object.assign(
        payload,
        extractParentLinkIdentifiers(requirement),
        extractParentLinkIdentifiers(entry),
      )

      pieceLinksPayload.push(payload)
    })
  }

  if (errors.length > 0) {
    return { valid: false, error: errors[0] }
  }

  return {
    valid: true,
    componentLinks: componentLinksPayload,
    pieceLinks: pieceLinksPayload,
  }
}

const applySkeletonReconfigurationResult = async (data) => {
  if (!data) return

  const updatedMachine = data.machine || data
  if (updatedMachine) {
    machine.value = {
      ...machine.value,
      ...updatedMachine,
      documents: updatedMachine.documents || machine.value?.documents || [],
    }
    initMachineFields()
    machineDocumentsLoaded.value = !!(machine.value.documents?.length)
  }

  const linksApplied = applyMachineLinks(data) || applyMachineLinks(updatedMachine)
  if (linksApplied) {
    if (machine.value) {
      machine.value.componentLinks = machineComponentLinks.value
      machine.value.pieceLinks = machinePieceLinks.value
    }
    collapseAllComponents()
    return
  }

  const newComponents = data.components ?? updatedMachine?.components ?? null
  if (Array.isArray(newComponents)) {
    components.value = transformComponentCustomFields(newComponents)
    collapseAllComponents()
  }

  const newPieces = data.pieces ?? updatedMachine?.pieces ?? null
  if (Array.isArray(newPieces)) {
    pieces.value = transformCustomFields(newPieces)
  }

}

const saveSkeletonConfiguration = async () => {
  if (!machine.value?.id) {
    return
  }

  const type = machineType.value
  let payload = { componentLinks: [], pieceLinks: [] }

  if (type && machineHasSkeletonRequirements.value) {
    const validation = validateSkeletonSelections(type)
    if (!validation.valid) {
      toast.showError(validation.error)
      return
    }
    payload = {
      componentLinks: validation.componentLinks,
      pieceLinks: validation.pieceLinks,
    }
  }

  skeletonEditor.submitting = true
  try {
    const result = await reconfigureMachineSkeleton(machine.value.id, payload)
    if (result.success) {
      await applySkeletonReconfigurationResult(result.data)
      await changeMachineView('details')
    } else if (result.error) {
      toast.showError(result.error)
    }
  } catch (error) {
    console.error('Erreur lors de la reconfiguration du squelette de la machine:', error)
    toast.showError('Erreur lors de la mise à jour des éléments du squelette')
  } finally {
    skeletonEditor.submitting = false
    skeletonEditor.loading = false
  }
}

const handleMachineConstructeurChange = async (value) => {
  machineConstructeurId.value = value
  await updateMachineInfo()
}

// Mode d'édition
const isEditMode = ref(false)
const debug = ref(false) // Ajout de debug pour afficher les infos de debug

const machineViewTitle = computed(() => {
  if (isSkeletonView.value) {
    return 'Squelette de la machine'
  }
  return isEditMode.value ? 'Modification de la machine' : 'Détails de la machine'
})

// Gestion du pliage global des composants
const componentsCollapsed = ref(true)
const collapseToggleToken = ref(0)

const toggleAllComponents = () => {
  componentsCollapsed.value = !componentsCollapsed.value
  collapseToggleToken.value += 1
}

const collapseAllComponents = () => {
  componentsCollapsed.value = true
  collapseToggleToken.value += 1
}

// Méthodes pour initialiser les champs
const initMachineFields = () => {
  if (machine.value) {
    machineName.value = machine.value.name || ''
    machineReference.value = machine.value.reference || ''
    machineConstructeurId.value = machine.value.constructeurId || machine.value.constructeur?.id || null
  }
}

// Fonctions pour générer des IDs uniques
const getMachineFieldId = (fieldName) => {
  return machine.value ? `machine-${fieldName}-${machine.value.id}` : `machine-${fieldName}`
}

// Computed
const machinePieces = computed(() => {
  const filteredPieces = pieces.value.filter((piece) => {
    const parentLinkId = resolveIdentifier(
      piece.parentComponentLinkId,
      piece.machinePieceLink?.parentComponentLinkId,
      piece.parentLinkId,
    )
    if (parentLinkId) {
      return false
    }
    return !piece.composantId
  })
  return filteredPieces
})

const machineDocumentsList = computed(() => machine.value?.documents || [])
const documentIcon = (doc) => getFileIcon({ name: doc.filename || doc.name, mime: doc.mimeType })

const flattenComponents = (list = []) => {
  const result = []
  const traverse = (items) => {
    items.forEach((item) => {
      result.push(item)
      if (item.subComponents && item.subComponents.length) {
        traverse(item.subComponents)
      }
    })
  }
  traverse(list)
  const filtered = result.filter((field) => {
    const key =
      field.customFieldId
        || field.id
        || (field.name ? `${field.name}::${field.type}` : null)

    if (!key) {
      return false
    }

    if (allowedKeys.size > 0) {
      return allowedKeys.has(key)
    }

    return true
  })

  return filtered
}

const flattenedComponents = computed(() => flattenComponents(components.value))

const componentRequirementGroups = computed(() => {
  const requirements = machine.value?.typeMachine?.componentRequirements || []
  if (!requirements.length) return []

  const groups = requirements.map((requirement) => ({
    requirement,
    components: [],
  }))

  const map = new Map(groups.map((group) => [group.requirement.id, group]))

  flattenedComponents.value.forEach((component) => {
    const reqId = component.typeMachineComponentRequirementId
    if (reqId && map.has(reqId)) {
      map.get(reqId).components.push(component)
    }
  })

  return groups
})

const pieceRequirementGroups = computed(() => {
  const requirements = machine.value?.typeMachine?.pieceRequirements || []
  if (!requirements.length) return []

  const groups = requirements.map((requirement) => ({
    requirement,
    pieces: [],
  }))

  const map = new Map(groups.map((group) => [group.requirement.id, group]))

  const collectPieces = () => {
    const collected = []

    // Pièces rattachées à la machine directement
    machinePieces.value.forEach((piece) => {
      collected.push({ ...piece, parentComponentName: null })
    })

    // Pièces rattachées aux composants
    flattenedComponents.value.forEach((component) => {
      if (component.pieces && component.pieces.length) {
        component.pieces.forEach((piece) => {
          collected.push({ ...piece, parentComponentName: component.name })
        })
      }
    })

    return collected
  }

  collectPieces().forEach((piece) => {
    const reqId = piece.typeMachinePieceRequirementId
    if (reqId && map.has(reqId)) {
      map.get(reqId).pieces.push(piece)
    }
  })

  return groups
})

const findComponentById = (items, id) => {
  for (const item of items || []) {
    if (item.id === id) return item
    const found = findComponentById(item.subComponents, id)
    if (found) return found
  }
  return null
}

const findPieceById = (pieceId) => {
  const direct = pieces.value.find((piece) => piece.id === pieceId)
  if (direct) return direct

  const searchInComponents = (items) => {
    for (const item of items || []) {
      const match = (item.pieces || []).find((piece) => piece.id === pieceId)
      if (match) return match
      const nested = searchInComponents(item.subComponents)
      if (nested) return nested
    }
    return null
  }

  return searchInComponents(components.value)
}

const refreshMachineDocuments = async () => {
  if (!machine.value?.id) return
  const result = await loadDocumentsByMachine(machine.value.id, { updateStore: false })
  if (result.success && machine.value) {
    machine.value.documents = result.data || []
    machineDocumentsLoaded.value = true
  }
}

const handleMachineFilesAdded = async (files) => {
  if (!files.length || !machine.value?.id) return
  machineDocumentsUploading.value = true
  try {
    const result = await uploadDocuments(
      {
        files,
        context: { machineId: machine.value.id }
      },
      { updateStore: false }
    )

    if (result.success && machine.value) {
      const newDocs = result.data || []
      machine.value.documents = [...newDocs, ...(machine.value.documents || [])]
      machineDocumentFiles.value = []
    }
  } finally {
    machineDocumentsUploading.value = false
  }
}

const removeMachineDocument = async (documentId) => {
  if (!documentId) return
  const result = await deleteDocument(documentId, { updateStore: false })
  if (result.success && machine.value) {
    machine.value.documents = (machine.value.documents || []).filter(doc => doc.id !== documentId)
  }
}

const downloadDocument = (doc) => {
  if (!doc?.path) return

  if (doc.path.startsWith('data:')) {
    const link = document.createElement('a')
    link.href = doc.path
    link.download = doc.filename || doc.name || 'document'
    link.click()
    return
  }

  window.open(doc.path, '_blank')
}

const openPreview = (doc) => {
  if (!canPreviewDocument(doc)) return
  previewDocument.value = doc
  previewVisible.value = true
}

const closePreview = () => {
  previewVisible.value = false
  previewDocument.value = null
}

const ensurePrintSelectionEntries = () => {
  printSelection.machine.info ??= true
  printSelection.machine.customFields ??= true
  printSelection.machine.documents ??= true

  const ensureComponent = (component) => {
    if (component?.id !== undefined && printSelection.components[component.id] === undefined) {
      printSelection.components[component.id] = true
    }
    ;(component.pieces || []).forEach((piece) => {
      if (piece?.id !== undefined && printSelection.pieces[piece.id] === undefined) {
        printSelection.pieces[piece.id] = true
      }
    })
    ;(component.subComponents || []).forEach(ensureComponent)
  }

  components.value.forEach(ensureComponent)
  machinePieces.value.forEach((piece) => {
    if (piece?.id !== undefined && printSelection.pieces[piece.id] === undefined) {
      printSelection.pieces[piece.id] = true
    }
  })
}

const setAllPrintSelection = (value) => {
  ensurePrintSelectionEntries()
  printSelection.machine.info = value
  printSelection.machine.customFields = value
  printSelection.machine.documents = value
  Object.keys(printSelection.components).forEach((key) => {
    printSelection.components[key] = value
  })
  Object.keys(printSelection.pieces).forEach((key) => {
    printSelection.pieces[key] = value
  })
}

const openPrintModal = () => {
  ensurePrintSelectionEntries()
  printModalOpen.value = true
}

const closePrintModal = () => {
  printModalOpen.value = false
}

const handlePrintConfirm = async () => {
  closePrintModal()
  await nextTick()
  printMachine(printSelection)
}


const printMachine = (currentSelection = printSelection) => {
  if (typeof window === 'undefined') return

  const context = buildMachinePrintContext({
    machine: machine.value,
    machineName: machineName.value,
    machineReference: machineReference.value,
    machinePieces: machinePieces.value,
    components: components.value,
    selection: currentSelection,
  })
  const styles = Array.from(document.querySelectorAll('link[rel="stylesheet"], style'))
    .map(node => node.outerHTML)
    .join('')

  const htmlContent = buildMachinePrintHtml(context, styles)

  const iframe = document.createElement('iframe')
  iframe.style.position = 'fixed'
  iframe.style.right = '0'
  iframe.style.bottom = '0'
  iframe.style.width = '0'
  iframe.style.height = '0'
  iframe.style.border = '0'
  iframe.setAttribute('title', 'print-frame')
  document.body.appendChild(iframe)

  const iframeWindow = iframe.contentWindow
  const iframeDocument = iframe.contentDocument || iframeWindow?.document
  if (!iframeDocument || !iframeWindow) {
    iframe.remove()
    return
  }

  iframeDocument.open()
  iframeDocument.write(htmlContent)
  iframeDocument.close()

  const triggerPrint = () => {
    iframeWindow.focus()
    iframeWindow.print()
    setTimeout(() => {
      iframe.remove()
    }, 1000)
  }

  if (iframeDocument.readyState === 'complete') {
    setTimeout(triggerPrint, 50)
  } else {
    iframe.onload = () => setTimeout(triggerPrint, 50)
  }
}

const formatSize = (size) => {
  if (size === undefined || size === null) return '—'
  if (size === 0) return '0 B'
  const units = ['B', 'KB', 'MB', 'GB']
  const index = Math.min(units.length - 1, Math.floor(Math.log(size) / Math.log(1024)))
  const formatted = size / Math.pow(1024, index)
  return `${formatted.toFixed(1)} ${units[index]}`
}

const PDF_PREVIEW_MAX_BYTES = 5 * 1024 * 1024

const shouldInlinePdf = (document) => {
  if (!document || !isPdfDocument(document) || !document.path) {
    return false
  }
  if (typeof document.size === 'number' && document.size > PDF_PREVIEW_MAX_BYTES) {
    return false
  }
  return true
}

const appendPdfViewerParams = (src) => {
  if (!src || src.startsWith('data:')) {
    return src || ''
  }
  if (src.includes('#')) {
    return `${src}&toolbar=0&navpanes=0`
  }
  return `${src}#toolbar=0&navpanes=0`
}

const documentPreviewSrc = (document) => {
  if (!document?.path) {
    return ''
  }
  if (isPdfDocument(document)) {
    return appendPdfViewerParams(document.path)
  }
  return document.path
}

const documentThumbnailClass = (document) => {
  if (shouldInlinePdf(document) || (isImageDocument(document) && document?.path)) {
    return 'h-24 w-20'
  }
  return 'h-16 w-16'
}

const formatCustomFieldValue = (field) => {
  if (!field) {
    return 'Non défini'
  }

  const value = field.value ?? field.defaultValue ?? ''
  if (value === '' || value === null || value === undefined) {
    return 'Non défini'
  }

  if (field.type === 'boolean') {
    const normalized = String(value).toLowerCase()
    if (normalized === 'true' || normalized === '1') return 'Oui'
    if (normalized === 'false' || normalized === '0') return 'Non'
  }

  return String(value)
}

const shouldDisplayCustomField = (field) => {
  if (!field) {
    return false
  }

  if (field.readOnly) {
    return true
  }

  if (field.type === 'boolean') {
    return field.value !== undefined && field.value !== null
  }

  const value = field.value
  if (value === null || value === undefined) {
    return false
  }

  if (typeof value === 'string') {
    return value.trim().length > 0
  }

  return true
}

const visibleMachineCustomFields = computed(() => {
  const fields = Array.isArray(machineCustomFields.value) ? machineCustomFields.value : []
  if (isEditMode.value) {
    return fields
  }
  return fields.filter((field) => shouldDisplayCustomField(field))
})

const summarizeCustomFields = (fields = []) => {
  const seen = new Set()
  return fields
    .filter(shouldDisplayCustomField)
    .filter((field) => {
      const key = field.customFieldId || field.id || field.name
      if (!key) {
        return true
      }
      if (seen.has(key)) {
        return false
      }
      seen.add(key)
      return true
    })
    .map((field, index) => ({
      key: field.customFieldId || field.id || field.name || `custom-field-${index}`,
      label: field.name || 'Champ',
      value: formatCustomFieldValue(field),
    }))
}

const extractDefinitionName = (definition = {}) => {
  if (typeof definition?.name === 'string' && definition.name.trim()) {
    return definition.name.trim()
  }
  if (typeof definition?.key === 'string' && definition.key.trim()) {
    return definition.key.trim()
  }
  if (typeof definition?.label === 'string' && definition.label.trim()) {
    return definition.label.trim()
  }
  return ''
}

const extractDefinitionType = (definition = {}, fallback = 'text') => {
  const allowed = ['text', 'number', 'select', 'boolean', 'date']
  const rawType =
    typeof definition?.type === 'string'
      ? definition.type
      : typeof definition?.value?.type === 'string'
        ? definition.value.type
        : typeof fallback === 'string'
          ? fallback
          : 'text'
  const normalized = rawType.toLowerCase()
  return allowed.includes(normalized) ? normalized : 'text'
}

const extractDefinitionRequired = (definition = {}, fallback = false) => {
  if (typeof definition?.required === 'boolean') {
    return definition.required
  }
  const nested = definition?.value?.required
  if (typeof nested === 'boolean') {
    return nested
  }
  if (typeof nested === 'string') {
    const normalized = nested.toLowerCase()
    if (normalized === 'true' || normalized === '1') {
      return true
    }
    if (normalized === 'false' || normalized === '0') {
      return false
    }
  }
  return !!fallback
}

const extractOptionList = (input) => {
  if (!Array.isArray(input)) {
    return undefined
  }
  const mapped = input
    .map((option) => {
      if (option === null || option === undefined) {
        return ''
      }
      if (typeof option === 'string') {
        return option.trim()
      }
      if (typeof option === 'object') {
        const record = option || {}
        const keys = ['value', 'label', 'name']
        for (const key of keys) {
          const candidate = record[key]
          if (typeof candidate === 'string' && candidate.trim().length > 0) {
            return candidate.trim()
          }
        }
      }
      const fallback = String(option).trim()
      return fallback === '[object Object]' ? '' : fallback
    })
    .filter((option) => option.length > 0)
  return mapped.length ? mapped : undefined
}

const extractDefinitionOptions = (definition = {}) => {
  const sources = [definition?.options, definition?.value?.options, definition?.value?.choices]
  for (const source of sources) {
    const list = extractOptionList(source)
    if (list) {
      return list
    }
  }
  return []
}

const extractDefinitionDefaultValue = (definition = {}) => {
  const candidates = [
    definition?.defaultValue,
    definition?.value?.defaultValue,
    definition?.value?.value,
    definition?.value,
    definition?.default,
  ]
  for (const candidate of candidates) {
    if (candidate === undefined || candidate === null || candidate === '') {
      continue
    }
    if (typeof candidate === 'object') {
      if (candidate === null) {
        continue
      }
      if (candidate && typeof candidate === 'object') {
        const nestedDefault =
          candidate.defaultValue !== undefined && candidate.defaultValue !== null
            ? candidate.defaultValue
            : candidate.value
        if (nestedDefault !== undefined && nestedDefault !== null && nestedDefault !== '') {
          return nestedDefault
        }
      }
      continue
    }
    return candidate
  }
  return undefined
}

const coerceValueForType = (type, rawValue) => {
  if (rawValue === undefined || rawValue === null || rawValue === '') {
    return ''
  }
  if (type === 'boolean') {
    const normalized = String(rawValue).toLowerCase()
    if (normalized === 'true' || normalized === '1') {
      return 'true'
    }
    if (normalized === 'false' || normalized === '0') {
      return 'false'
    }
    return ''
  }
  return String(rawValue)
}

const normalizeExistingCustomFieldDefinitions = (fields) => {
  if (!Array.isArray(fields)) {
    return []
  }
  return fields
    .map((field) => normalizeCustomFieldDefinitionEntry(field))
    .filter((definition) => definition !== null)
}

const normalizeCustomFieldDefinitionEntry = (definition = {}) => {
  const name = extractDefinitionName(definition)
  if (!name) {
    return null
  }
  const type = extractDefinitionType(definition)
  const required = extractDefinitionRequired(definition)
  const options = extractDefinitionOptions(definition)
  const defaultValue = extractDefinitionDefaultValue(definition)
  const id = typeof definition?.id === 'string' ? definition.id : undefined
  const customFieldId = typeof definition?.customFieldId === 'string' ? definition.customFieldId : id
  return {
    id,
    customFieldId,
    name,
    type,
    required,
    options,
    defaultValue,
    readOnly: !!definition?.readOnly,
  }
}

const getStructureCustomFields = (structure) => {
  if (!structure || typeof structure !== 'object') {
    return []
  }
  const normalized = normalizeStructureForEditor(structure)
  return Array.isArray(normalized.customFields) ? normalized.customFields : []
}

// Transform custom field values to custom fields format
const normalizeCustomFieldValueEntry = (entry = {}) => {
  if (!entry || typeof entry !== 'object') {
    return null
  }

  const normalizedDefinition = normalizeCustomFieldDefinitionEntry(entry)
  if (!normalizedDefinition) {
    return null
  }

  const value = coerceValueForType(
    normalizedDefinition.type,
    entry?.value ?? entry?.defaultValue ?? normalizedDefinition.defaultValue ?? '',
  )

  return {
    id: entry?.customFieldValueId ?? entry?.id ?? null,
    customFieldId:
      entry?.customFieldId
      ?? normalizedDefinition.customFieldId
      ?? normalizedDefinition.id
      ?? null,
    customField: {
      id: normalizedDefinition.id ?? normalizedDefinition.customFieldId ?? null,
      name: normalizedDefinition.name,
      type: normalizedDefinition.type,
      required: normalizedDefinition.required,
      options: normalizedDefinition.options,
      defaultValue: normalizedDefinition.defaultValue ?? '',
    },
    value,
  }
}

const mergeCustomFieldValuesWithDefinitions = (valueEntries = [], ...definitionSources) => {
  const normalizedValues = (Array.isArray(valueEntries) ? valueEntries : [])
    .map((entry) => {
      if (!entry || typeof entry !== 'object') {
        return null
      }

      const normalizedDefinition = normalizeCustomFieldDefinitionEntry(entry.customField || entry)
      if (!normalizedDefinition) {
        return null
      }

      const value = coerceValueForType(
        normalizedDefinition.type,
        entry?.value ?? entry?.defaultValue ?? normalizedDefinition.defaultValue ?? '',
      )

      return {
        customFieldValueId: entry?.id ?? entry?.customFieldValueId ?? null,
        id: normalizedDefinition.id,
        customFieldId: normalizedDefinition.customFieldId ?? normalizedDefinition.id ?? null,
        name: normalizedDefinition.name,
        type: normalizedDefinition.type,
        required: normalizedDefinition.required,
        options: normalizedDefinition.options,
        optionsText: normalizedDefinition.options?.length ? normalizedDefinition.options.join('\n') : '',
        defaultValue: normalizedDefinition.defaultValue ?? '',
        value,
        readOnly: !!entry?.readOnly,
      }
    })
    .filter((entry) => entry !== null)

  const result = [...normalizedValues]
  const keyFor = (item) => item?.id ?? `${item?.name ?? ''}::${item?.type ?? ''}`
  const existingMap = new Map()
  result.forEach((item) => {
    const key = keyFor(item)
    if (key) {
      existingMap.set(key, item)
    }
    const fallbackKey = item?.name ? `${item.name}::${item.type ?? ''}` : null
    if (fallbackKey) {
      existingMap.set(fallbackKey, item)
    }
  })

  const definitions = definitionSources
    .flatMap((source) => (Array.isArray(source) ? source : []))
    .map((definition) => normalizeCustomFieldDefinitionEntry(definition))
    .filter((definition) => definition !== null)

  const allowedKeys = new Set()
  definitions.forEach((definition) => {
    if (!definition) {
      return
    }
    if (definition.id) {
      allowedKeys.add(definition.id)
    }
    if (definition.customFieldId) {
      allowedKeys.add(definition.customFieldId)
    }
    if (definition.name) {
      allowedKeys.add(`${definition.name}::${definition.type}`)
    }
  })

  definitions.forEach((normalizedDefinition) => {
    const key = normalizedDefinition.id ?? `${normalizedDefinition.name}::${normalizedDefinition.type}`
    if (!key) {
      return
    }
    if (normalizedDefinition.id) {
      const fallbackKey = `${normalizedDefinition.name}::${normalizedDefinition.type}`
      if (existingMap.has(fallbackKey)) {
        const existingFallback = existingMap.get(fallbackKey)
      if (existingFallback) {
        existingFallback.id = existingFallback.id || normalizedDefinition.id
        existingFallback.customFieldId = normalizedDefinition.id
        existingFallback.readOnly = existingFallback.readOnly && normalizedDefinition.readOnly
        existingMap.delete(fallbackKey)
        existingMap.set(normalizedDefinition.id, existingFallback)
        existingMap.set(fallbackKey, existingFallback)
        return
      }
    }
    }
    const existing = existingMap.get(key) || (normalizedDefinition.name
      ? existingMap.get(`${normalizedDefinition.name}::${normalizedDefinition.type}`)
      : null)
    if (existing) {
      existing.name = existing.name || normalizedDefinition.name
      existing.type = existing.type || normalizedDefinition.type
      existing.required = existing.required || normalizedDefinition.required
      if (!existing.options?.length && normalizedDefinition.options?.length) {
        existing.options = normalizedDefinition.options
      }
      if (!existing.defaultValue && normalizedDefinition.defaultValue) {
        existing.defaultValue = String(normalizedDefinition.defaultValue)
        if (!existing.value) {
          existing.value = coerceValueForType(existing.type, normalizedDefinition.defaultValue)
        }
      }
      existing.customFieldId = existing.customFieldId || normalizedDefinition.id
      existing.readOnly = existing.readOnly && normalizedDefinition.readOnly
      if (!existing.optionsText && normalizedDefinition.options?.length) {
        existing.optionsText = normalizedDefinition.options.join('\n')
      }
      if (normalizedDefinition.id) {
        existingMap.set(normalizedDefinition.id, existing)
      }
      if (normalizedDefinition.name) {
        existingMap.set(`${normalizedDefinition.name}::${normalizedDefinition.type}`, existing)
      }
      return
    }

    const entry = {
      customFieldValueId: null,
      id: normalizedDefinition.id,
      customFieldId: normalizedDefinition.id,
      name: normalizedDefinition.name,
      type: normalizedDefinition.type,
      required: normalizedDefinition.required,
      options: normalizedDefinition.options,
      optionsText: normalizedDefinition.options?.length ? normalizedDefinition.options.join('\n') : '',
      defaultValue: normalizedDefinition.defaultValue ?? '',
      value: coerceValueForType(normalizedDefinition.type, normalizedDefinition.defaultValue ?? ''),
      readOnly: false,
    }
    result.push(entry)
    existingMap.set(key, entry)
    const fallbackKey = entry.name ? `${entry.name}::${entry.type}` : null
    if (fallbackKey) {
      existingMap.set(fallbackKey, entry)
    }
  })

  return result
}

const dedupeCustomFieldEntries = (fields) => {
  if (!Array.isArray(fields) || fields.length <= 1) {
    return Array.isArray(fields) ? fields : []
  }

  const seen = new Set()
  const result = []

  for (const field of fields) {
    if (!field) {
      continue
    }

    field.type = field.type || 'text'

    let normalizedName =
      typeof field.name === 'string' ? field.name.trim() : ''

    if (!normalizedName && field.customField?.name) {
      normalizedName = String(field.customField.name).trim()
      field.name = normalizedName
    } else if (typeof field.name === 'string') {
      field.name = normalizedName
    }

    const key =
      field.customFieldId ||
      field.id ||
      (normalizedName ? `${normalizedName}::${field.type || 'text'}` : null)

    if (!key && !normalizedName) {
      continue
    }

    if (key && seen.has(key)) {
      continue
    }

    if (!normalizedName) {
      continue
    }

    if (key) {
      seen.add(key)
    }
    if (normalizedName) {
      seen.add(`${normalizedName}::${field.type || 'text'}`)
    }
    result.push(field)
  }

  return result
}

const transformCustomFields = (pieces) => {
  return (pieces || []).map((piece) => {
    const requirement = piece.typeMachinePieceRequirement || {}
    const typePiece = requirement.typePiece || piece.typePiece || {}

    const normalizeStructureDefinitions = (structure) => (
      structure ? normalizeStructureForEditor(structure) : null
    )

    const normalizedStructureDefinitions = [
      normalizeStructureDefinitions(piece.definition?.structure),
      normalizeStructureDefinitions(piece.typePiece?.structure),
      normalizeStructureDefinitions(typePiece.structure),
      normalizeStructureDefinitions(typePiece.pieceSkeleton),
      normalizeStructureDefinitions(piece.typePiece?.pieceSkeleton),
      normalizeStructureDefinitions(requirement.structure),
      normalizeStructureDefinitions(requirement.pieceSkeleton),
    ]

    const valueEntries = [
      ...(Array.isArray(piece.customFieldValues) ? piece.customFieldValues : []),
      ...(Array.isArray(piece.customFields)
        ? piece.customFields
            .map(normalizeCustomFieldValueEntry)
            .filter((entry) => entry !== null)
        : []),
      ...(Array.isArray(typePiece.customFieldValues)
        ? typePiece.customFieldValues
            .map(normalizeCustomFieldValueEntry)
            .filter((entry) => entry !== null)
        : []),
    ]

    const customFields = dedupeCustomFieldEntries(
      mergeCustomFieldValuesWithDefinitions(
        valueEntries,
        normalizeExistingCustomFieldDefinitions(piece.customFields),
        normalizeExistingCustomFieldDefinitions(piece.definition?.customFields),
        normalizeExistingCustomFieldDefinitions(piece.typePiece?.customFields),
        normalizeExistingCustomFieldDefinitions(typePiece.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.typePiece?.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.definition?.customFields),
        ...normalizedStructureDefinitions.map((definition) =>
          getStructureCustomFields(definition),
        ),
      ),
    )

    return {
      ...piece,
      customFields,
      documents: piece.documents || [],
      constructeur: piece.constructeur || null,
      constructeurId: piece.constructeurId || piece.constructeur?.id || null,
      typePieceId: piece.typePieceId
        || piece.typeMachinePieceRequirement?.typePieceId
        || piece.typePiece?.id
        || null,
    }
  })
}

// Transform custom fields for components (now handles nested structure)
const transformComponentCustomFields = (componentsData) => {
  const normalizeStructureDefinitions = (structure) => (
    structure ? normalizeStructureForEditor(structure) : null
  )

  return (componentsData || []).map((component) => {
    const requirement = component.typeMachineComponentRequirement || {}
    const type = requirement.typeComposant || component.typeComposant || {}

    const normalizedStructureDefinitions = [
      normalizeStructureDefinitions(component.definition?.structure),
      normalizeStructureDefinitions(component.typeComposant?.structure),
      normalizeStructureDefinitions(type.structure),
      normalizeStructureDefinitions(type.componentSkeleton),
      normalizeStructureDefinitions(requirement.structure),
      normalizeStructureDefinitions(requirement.componentSkeleton),
    ]

    const actualComponent = component.originalComposant || component

    const valueEntries = [
      ...(Array.isArray(component.customFieldValues) ? component.customFieldValues : []),
      ...(Array.isArray(component.customFields)
        ? component.customFields
            .map(normalizeCustomFieldValueEntry)
            .filter((entry) => entry !== null)
        : []),
      ...(Array.isArray(actualComponent?.customFields)
        ? actualComponent.customFields
            .map(normalizeCustomFieldValueEntry)
            .filter((entry) => entry !== null)
        : []),
    ]

    const customFields = dedupeCustomFieldEntries(
      mergeCustomFieldValuesWithDefinitions(
        valueEntries,
        normalizeExistingCustomFieldDefinitions(component.customFields),
        normalizeExistingCustomFieldDefinitions(component.definition?.customFields),
        normalizeExistingCustomFieldDefinitions(component.typeComposant?.customFields),
        normalizeExistingCustomFieldDefinitions(type.customFields),
        normalizeExistingCustomFieldDefinitions(actualComponent?.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.typeComposant?.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.customFields),
        normalizeExistingCustomFieldDefinitions(requirement.definition?.customFields),
        ...normalizedStructureDefinitions.map((definition) =>
          getStructureCustomFields(definition),
        ),
      ),
    )

    const pieces = component.pieces
      ? transformCustomFields(component.pieces).map((piece) => ({
          ...piece,
          parentComponentName: component.name,
        }))
      : []

    const subComponents = component.sousComposants
      ? transformComponentCustomFields(component.sousComposants)
      : []

    return {
      ...component,
      customFields,
      pieces,
      subComponents,
      documents: component.documents || [],
      constructeur: component.constructeur || null,
      constructeurId: component.constructeurId || component.constructeur?.id || null,
      typeComposantId: component.typeComposantId
        || component.typeMachineComponentRequirement?.typeComposantId
        || component.typeComposant?.id
        || null,
    }
  })
}

const syncMachineCustomFields = () => {
  if (!machine.value) {
    machineCustomFields.value = []
    return
  }

  const valueEntries = [
    ...(Array.isArray(machine.value.customFieldValues) ? machine.value.customFieldValues : []),
    ...(Array.isArray(machine.value.customFields)
      ? machine.value.customFields
          .map(normalizeCustomFieldValueEntry)
          .filter((entry) => entry !== null)
      : []),
  ]

  const merged = dedupeCustomFieldEntries(
    mergeCustomFieldValuesWithDefinitions(
      valueEntries,
      normalizeExistingCustomFieldDefinitions(machine.value.customFields),
      normalizeExistingCustomFieldDefinitions(machine.value.typeMachine?.customFields),
    ),
  ).map((field) => ({
    ...field,
    readOnly: false,
  }))

  machineCustomFields.value = merged
}

function mergePieceLists(existing = [], updates = []) {
  if (!existing.length) {
    return updates
  }
  if (!updates.length) {
    return existing
  }

  const updateMap = new Map(updates.map(piece => [piece.id, piece]))
  const merged = existing.map(piece => {
    const update = updateMap.get(piece.id)
    if (!update) {
      return piece
    }
    return {
      ...piece,
      ...update,
      customFields: update.customFields ?? piece.customFields,
    }
  })

  updates.forEach(update => {
    if (!existing.some(piece => piece.id === update.id)) {
      merged.push(update)
    }
  })

  return merged
}

function mergeComponentTrees(existing = [], updates = []) {
  if (!existing.length) {
    return updates
  }
  if (!updates.length) {
    return existing
  }

  const updateMap = new Map(updates.map(component => [component.id, component]))
  const merged = existing.map(component => {
    const update = updateMap.get(component.id)
    if (!update) {
      return component
    }
    return {
      ...component,
      ...update,
      customFields: update.customFields ?? component.customFields,
      pieces: mergePieceLists(component.pieces || [], update.pieces || []),
      subComponents: mergeComponentTrees(component.subComponents || [], update.subComponents || []),
    }
  })

  updates.forEach(update => {
    if (!existing.some(component => component.id === update.id)) {
      merged.push(update)
    }
  })

  return merged
}

const buildMachineHierarchyFromLinks = (componentLinks = [], pieceLinks = []) => {
  const normalizeComponentLinkId = (link) =>
    resolveIdentifier(link?.id, link?.linkId, link?.machineComponentLinkId)

  const normalizePieceLinkId = (link) =>
    resolveIdentifier(link?.id, link?.linkId, link?.machinePieceLinkId)

  const createPieceNode = (link, parentComponentName = null) => {
    if (!link || typeof link !== 'object') {
      return null
    }

    const appliedPiece =
      (link.piece && typeof link.piece === 'object' && link.piece) || {}
    const originalPiece =
      (link.originalPiece && typeof link.originalPiece === 'object' && link.originalPiece) || null

    const requirement =
      link.typeMachinePieceRequirement ||
      appliedPiece.typeMachinePieceRequirement ||
      originalPiece?.typeMachinePieceRequirement ||
      null

    const machinePieceLinkId = normalizePieceLinkId(link)
    const pieceId = resolveIdentifier(appliedPiece.id, appliedPiece.pieceId, link.pieceId)

    const basePiece = {
      ...appliedPiece,
      id: appliedPiece.id || pieceId || machinePieceLinkId || `piece-${machinePieceLinkId}`,
      pieceId,
      name:
        link.overrides?.name ||
        appliedPiece.name ||
        appliedPiece.definition?.name ||
        appliedPiece.definition?.role ||
        originalPiece?.name ||
        'Pièce',
      reference:
        link.overrides?.reference ||
        appliedPiece.reference ||
        appliedPiece.definition?.reference ||
        originalPiece?.reference ||
        null,
      prix:
        link.overrides?.prix ??
        appliedPiece.prix ??
        originalPiece?.prix ??
        null,
      constructeur:
        appliedPiece.constructeur ||
        originalPiece?.constructeur ||
        null,
      constructeurId:
        appliedPiece.constructeurId ||
        appliedPiece.constructeur?.id ||
        originalPiece?.constructeurId ||
        null,
      documents:
        Array.isArray(appliedPiece.documents)
          ? appliedPiece.documents
          : Array.isArray(originalPiece?.documents)
            ? originalPiece.documents
            : [],
      typePiece: appliedPiece.typePiece || requirement?.typePiece || null,
      typePieceId:
        appliedPiece.typePieceId ||
        appliedPiece.typePiece?.id ||
        requirement?.typePieceId ||
        requirement?.typePiece?.id ||
        null,
      typeMachinePieceRequirement: requirement,
      typeMachinePieceRequirementId: requirement?.id || null,
      requirementId: requirement?.id || null,
      overrides: link.overrides || null,
      originalPiece,
      machinePieceLink: link,
      machinePieceLinkId,
      linkId: machinePieceLinkId,
      parentComponentLinkId: resolveIdentifier(
        link.parentComponentLinkId,
        link.parentLinkId,
        link.parentMachineComponentLinkId,
        appliedPiece.parentComponentLinkId,
      ),
      parentComponentId: resolveIdentifier(
        appliedPiece.parentComponentId,
        link.parentComponentId,
      ),
      parentComponentName,
      parentLinkId: resolveIdentifier(
        link.parentLinkId,
        link.parentMachinePieceLinkId,
        appliedPiece.parentLinkId,
      ),
      parentPieceLinkId: resolveIdentifier(
        link.parentPieceLinkId,
        appliedPiece.parentPieceLinkId,
      ),
      parentPieceId: resolveIdentifier(
        appliedPiece.parentPieceId,
        link.parentPieceId,
      ),
      parentMachineComponentRequirementId: resolveIdentifier(
        appliedPiece.parentMachineComponentRequirementId,
        link.parentMachineComponentRequirementId,
      ),
      parentMachinePieceRequirementId: resolveIdentifier(
        appliedPiece.parentMachinePieceRequirementId,
        link.parentMachinePieceRequirementId,
      ),
      definition: appliedPiece.definition || originalPiece?.definition || {},
      customFields: appliedPiece.customFields || [],
      skeletonOnly: !pieceId,
    }

    return basePiece
  }

  const createComponentNode = (link) => {
    if (!link || typeof link !== 'object') {
      return null
    }

    const appliedComponent =
      (link.composant && typeof link.composant === 'object' && link.composant) || {}
    const originalComponent =
      (link.originalComposant && typeof link.originalComposant === 'object' && link.originalComposant) || null

    const requirement =
      link.typeMachineComponentRequirement ||
      appliedComponent.typeMachineComponentRequirement ||
      originalComponent?.typeMachineComponentRequirement ||
      null

    const machineComponentLinkId = normalizeComponentLinkId(link)
    const composantId = resolveIdentifier(
      appliedComponent.id,
      appliedComponent.composantId,
      link.composantId,
    )

    const componentName =
      link.overrides?.name ||
      appliedComponent.name ||
      appliedComponent.definition?.alias ||
      appliedComponent.definition?.name ||
      originalComponent?.name ||
      'Composant'

    const pieces = Array.isArray(link.pieceLinks)
      ? link.pieceLinks.map((pieceLink) => createPieceNode(pieceLink, componentName)).filter(Boolean)
      : []

    const subComponents = Array.isArray(link.childLinks)
      ? link.childLinks.map(createComponentNode).filter(Boolean)
      : []

    const baseComponent = {
      ...appliedComponent,
      id: appliedComponent.id || composantId || machineComponentLinkId || `component-${machineComponentLinkId}`,
      composantId,
      name: componentName,
      reference:
        link.overrides?.reference ||
        appliedComponent.reference ||
        appliedComponent.definition?.reference ||
        originalComponent?.reference ||
        null,
      prix:
        link.overrides?.prix ??
        appliedComponent.prix ??
        originalComponent?.prix ??
        null,
      constructeur:
        appliedComponent.constructeur ||
        originalComponent?.constructeur ||
        null,
      constructeurId:
        appliedComponent.constructeurId ||
        appliedComponent.constructeur?.id ||
        originalComponent?.constructeurId ||
        null,
      documents:
        Array.isArray(appliedComponent.documents)
          ? appliedComponent.documents
          : Array.isArray(originalComponent?.documents)
            ? originalComponent.documents
            : [],
      typeComposant:
        appliedComponent.typeComposant ||
        requirement?.typeComposant ||
        null,
      typeComposantId:
        appliedComponent.typeComposantId ||
        appliedComponent.typeComposant?.id ||
        requirement?.typeComposantId ||
        requirement?.typeComposant?.id ||
        null,
      typeMachineComponentRequirement: requirement,
      typeMachineComponentRequirementId: requirement?.id || null,
      requirementId: requirement?.id || null,
      overrides: link.overrides || null,
      machineComponentLinkOverrides: link.overrides || null,
      definitionOverrides: link.overrides || null,
      originalComposant: originalComponent,
      machineComponentLink: link,
      machineComponentLinkId,
      componentLinkId: machineComponentLinkId,
      parentComponentLinkId: resolveIdentifier(
        link.parentComponentLinkId,
        link.parentLinkId,
        link.parentMachineComponentLinkId,
        appliedComponent.parentComponentLinkId,
      ),
      parentComposantId: resolveIdentifier(
        appliedComponent.parentComposantId,
        link.parentComponentId,
      ),
      parentRequirementId: resolveIdentifier(
        appliedComponent.parentRequirementId,
        link.parentRequirementId,
      ),
      parentMachineComponentRequirementId: resolveIdentifier(
        appliedComponent.parentMachineComponentRequirementId,
        link.parentMachineComponentRequirementId,
      ),
      parentMachinePieceRequirementId: resolveIdentifier(
        appliedComponent.parentMachinePieceRequirementId,
        link.parentMachinePieceRequirementId,
      ),
      definition: appliedComponent.definition || originalComponent?.definition || {},
      customFields: appliedComponent.customFields || [],
      pieces,
      subComponents,
      subcomponents: subComponents,
      sousComposants: subComponents,
      skeletonOnly: !composantId,
    }

    return baseComponent
  }

  const rootComponents = (Array.isArray(componentLinks) ? componentLinks : [])
    .filter((link) =>
      !resolveIdentifier(
        link?.parentComponentLinkId,
        link?.parentLinkId,
        link?.parentMachineComponentLinkId,
      ),
    )
    .map(createComponentNode)
    .filter(Boolean)

  const machinePieces = (Array.isArray(pieceLinks) ? pieceLinks : [])
    .filter((link) =>
      !resolveIdentifier(
        link?.parentComponentLinkId,
        link?.parentLinkId,
        link?.parentMachineComponentLinkId,
      ),
    )
    .map((link) => createPieceNode(link, null))
    .filter(Boolean)

  return {
    components: rootComponents,
    machinePieces,
  }
}

const resolveLinkArray = (source, keys) => {
  if (!source || typeof source !== 'object') {
    return null
  }
  for (const key of keys) {
    const value = source[key]
    if (Array.isArray(value)) {
      return value
    }
  }
  return null
}

const applyMachineLinks = (source) => {
  const container = source?.machine ?? null
  const componentLinks =
    resolveLinkArray(source, ['componentLinks', 'machineComponentLinks']) ??
    resolveLinkArray(container, ['componentLinks', 'machineComponentLinks'])
  const pieceLinks =
    resolveLinkArray(source, ['pieceLinks', 'machinePieceLinks']) ??
    resolveLinkArray(container, ['pieceLinks', 'machinePieceLinks'])

  if (componentLinks === null && pieceLinks === null) {
    return false
  }

  const normalizedComponentLinks = componentLinks ?? []
  const normalizedPieceLinks = pieceLinks ?? []

  machineComponentLinks.value = normalizedComponentLinks
  machinePieceLinks.value = normalizedPieceLinks

  const { components: hierarchy, machinePieces: machineLevelPieces } =
    buildMachineHierarchyFromLinks(normalizedComponentLinks, normalizedPieceLinks)

  components.value = transformComponentCustomFields(hierarchy)
  pieces.value = transformCustomFields(machineLevelPieces)

  return true
}

// Methods
const loadMachineData = async () => {
  loading.value = true
  try {
    const machineResult = await get(`/machines/${machineId}`)

    if (!machineResult.success) {
      console.error('Machine non trouvée:', machineId, machineResult.error)
      machine.value = null
      components.value = []
      pieces.value = []
      return
    }

    const machinePayload = machineResult.data?.machine && typeof machineResult.data.machine === 'object'
      ? machineResult.data.machine
      : machineResult.data

    if (!machinePayload || typeof machinePayload !== 'object') {
      console.error('Réponse machine invalide pour', machineId)
      machine.value = null
      components.value = []
      pieces.value = []
      return
    }

    machine.value = {
      ...machinePayload,
      documents: machinePayload.documents || [],
      customFieldValues: machinePayload.customFieldValues || [],
    }

    machineDocumentsLoaded.value = machine.value.documents.length > 0
    syncMachineCustomFields()
    initMachineFields()

    const linksApplied = applyMachineLinks(machineResult.data)

    if (machine.value) {
      machine.value.componentLinks = machineComponentLinks.value
      machine.value.pieceLinks = machinePieceLinks.value
    }

    if (!linksApplied) {
      components.value = transformComponentCustomFields(machinePayload.components || [])
      pieces.value = transformCustomFields(machinePayload.pieces || [])
    }

    collapseAllComponents()

    if (!machineDocumentsLoaded.value) {
      await refreshMachineDocuments()
    }
  } catch (error) {
    console.error('Erreur lors du chargement des données:', error)
  } finally {
    loading.value = false
  }
}

const updateMachineInfo = async () => {
  if (!machine.value) return

  try {
    const result = await updateMachineApi(machine.value.id, {
      name: machineName.value,
      reference: machineReference.value,
      constructeurId: machineConstructeurId.value || null
    })
    if (result.success) {
      const machinePayload = result.data?.machine && typeof result.data.machine === 'object'
        ? result.data.machine
        : result.data

      if (machinePayload && typeof machinePayload === 'object') {
        machine.value = {
          ...machine.value,
          ...machinePayload,
          documents: machinePayload.documents || machine.value.documents || [],
          customFieldValues: machinePayload.customFieldValues || machine.value.customFieldValues || [],
        }
        machineConstructeurId.value = machine.value.constructeurId || machine.value.constructeur?.id || null

        const linksApplied = applyMachineLinks(result.data)
        if (linksApplied && machine.value) {
          machine.value.componentLinks = machineComponentLinks.value
          machine.value.pieceLinks = machinePieceLinks.value
        }
      }
    }
  } catch (error) {
    console.error('Erreur lors de la mise à jour de la machine:', error)
  }
}

const updateComponent = async (updatedComponent) => {
  try {
    const prixValue = updatedComponent.prix
    const result = await updateComposantApi(updatedComponent.id, {
      name: updatedComponent.name,
      reference: updatedComponent.reference,
      constructeurId: updatedComponent.constructeurId || updatedComponent.constructeur?.id || null,
      prix: prixValue && prixValue !== '' ? parseFloat(prixValue) : null,
    })
    if (result.success) {
      const transformed = transformComponentCustomFields([result.data])[0]
      Object.assign(updatedComponent, transformed)
    }
  } catch (error) {
    console.error('Erreur lors de la mise à jour du composant:', error)
  }
}

const updatePieceFromComponent = async (updatedPiece) => {
  try {
    const result = await updatePieceApi(updatedPiece.id, {
      name: updatedPiece.name,
      reference: updatedPiece.reference,
      constructeurId: updatedPiece.constructeurId || updatedPiece.constructeur?.id || null,
      prix: updatedPiece.prix && updatedPiece.prix !== '' ? parseFloat(updatedPiece.prix) : null,
    })
    if (result.success) {
      const transformed = transformCustomFields([result.data])[0]
      Object.assign(updatedPiece, transformed)
      // Si la pièce a des champs personnalisés mis à jour, les traiter
      if (updatedPiece.customFields) {
        for (const field of updatedPiece.customFields) {
          if (field.value !== undefined) {
            await upsertCustomFieldValue(
              field.id,
              'piece',
              updatedPiece.id,
              field.value
            )
          }
        }
      }
    }
  } catch (error) {
    console.error('Erreur lors de la mise à jour de la pièce:', error)
  }
}

const updatePieceInfo = async (updatedPiece) => {
  try {
    const result = await updatePieceApi(updatedPiece.id, {
      name: updatedPiece.name,
      reference: updatedPiece.reference,
      constructeurId: updatedPiece.constructeurId || updatedPiece.constructeur?.id || null,
      prix: updatedPiece.prix && updatedPiece.prix !== '' ? parseFloat(updatedPiece.prix) : null,
    })
    if (result.success) {
      const transformed = transformCustomFields([result.data])[0]
      Object.assign(updatedPiece, transformed)
    }
  } catch (error) {
    console.error('Erreur lors de la mise à jour de la pièce:', error)
  }
}

// Méthodes pour les champs personnalisés de la machine
const setMachineCustomFieldValue = (field, value) => {
  if (!field) {
    return
  }

  field.value = value

  if (field.customFieldValueId && machine.value?.customFieldValues) {
    const stored = machine.value.customFieldValues.find((fv) => fv.id === field.customFieldValueId)
    if (stored) {
      stored.value = value
    }
  }
}

const updateMachineCustomField = async (field) => {
  if (!machine.value || !field) {
    return
  }

  const { id: customFieldId, customFieldValueId } = field
  const fieldLabel = field.name || 'Champ personnalisé'

  try {
    if (customFieldValueId) {
      const result = await updateCustomFieldValueApi(customFieldValueId, { value: field.value ?? '' })
      if (result.success) {
        toast.showSuccess(`Champ "${fieldLabel}" de la machine mis à jour avec succès`)
        syncMachineCustomFields()
      } else {
        toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
      }
      return
    }

    if (!customFieldId) {
      toast.showError('Impossible de mettre à jour ce champ personnalisé (identifiant manquant).')
      return
    }

    const result = await upsertCustomFieldValue(customFieldId, 'machine', machine.value.id, field.value ?? '')
    if (result.success) {
      const createdValue = result.data
      toast.showSuccess(`Champ "${fieldLabel}" de la machine mis à jour avec succès`)

      if (createdValue?.id) {
        if (!createdValue.customField) {
          createdValue.customField = {
            id: customFieldId,
            name: field.name,
            type: field.type,
            required: field.required,
            options: field.options,
          }
        }
        field.customFieldValueId = createdValue.id
        field.readOnly = false

        const existingValues = Array.isArray(machine.value.customFieldValues)
          ? machine.value.customFieldValues.filter((item) => item.id !== createdValue.id)
          : []

        machine.value.customFieldValues = [...existingValues, createdValue]
      }

      syncMachineCustomFields()
    } else {
      toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
    }
  } catch (error) {
    console.error('Erreur lors de la mise à jour du champ personnalisé de la machine:', error)
    toast.showError(`Erreur lors de la mise à jour du champ "${fieldLabel}"`)
  }
}

const updatePieceCustomField = async (fieldUpdate) => {
  const { showSuccess, showError } = useToast()

  try {
    const result = await upsertCustomFieldValue(
      fieldUpdate.fieldId,
      'piece',
      fieldUpdate.pieceId,
      fieldUpdate.value
    )
    if (result.success) {
      showSuccess(`Champ personnalisé mis à jour avec succès`)
    } else {
      showError(`Erreur lors de la mise à jour du champ personnalisé`)
    }
  } catch (error) {
    showError(`Erreur lors de la mise à jour du champ personnalisé`)
    console.error('Erreur lors de la mise à jour du champ personnalisé:', error)
  }
}

const editComponent = () => {
  toast.showInfo('La modification des composants sera bientôt disponible')
}

const editPiece = () => {
  toast.showInfo('La modification des pièces sera bientôt disponible')
}

const toggleEditMode = () => {
  isEditMode.value = !isEditMode.value
  debug.value = !debug.value // Inversez la valeur de debug
  if (isEditMode.value && !machineDocumentsLoaded.value) {
    refreshMachineDocuments()
  }
}

watch(
  () => machine.value?.customFieldValues,
  () => {
    syncMachineCustomFields()
  },
  { deep: true }
)

watch(
  () => machine.value?.customFields,
  () => {
    syncMachineCustomFields()
  },
  { deep: true }
)

watch(
  () => machine.value?.typeMachine?.customFields,
  () => {
    syncMachineCustomFields()
  },
  { deep: true }
)

watch(
  () => [components.value.length, machinePieces.value.length],
  () => {
    ensurePrintSelectionEntries()
  },
  { immediate: true }
)

// Lifecycle
onMounted(() => {
  loadMachineData()
  if (!constructeurs.value.length) {
    loadConstructeurs()
  }
  if (!componentTypes.value.length) {
    loadComponentTypes()
  }
  if (!pieceTypes.value.length) {
    loadPieceTypes()
  }

  // Vérifier si on doit activer le mode édition depuis l'URL
  const route = useRoute()
  if (route.query.edit === 'true') {
    isEditMode.value = true
  }
})
</script> 
