/**
 * Machine detail page — core state & business logic (orchestrator).
 *
 * Extracted from pages/machine/[id].vue (F1.1).
 * Composes sub-composables for documents, custom fields, hierarchy and products.
 */

import { ref, computed, watch } from 'vue'
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 { useConstructeurs } from '~/composables/useConstructeurs'
import { useSites } from '~/composables/useSites'
import { useMachinePrint } from '~/composables/useMachinePrint'
import {
  resolveConstructeurs,
  uniqueConstructeurIds,
  formatConstructeurContact as formatConstructeurContactSummary,
  parseConstructeurLinksFromApi,
  constructeurIdsFromLinks,
} from '~/shared/constructeurUtils'
import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils'
import { useConstructeurLinks } from '~/composables/useConstructeurLinks'
import { useMachineDetailDocuments } from '~/composables/useMachineDetailDocuments'
import { useMachineDetailCustomFields } from '~/composables/useMachineDetailCustomFields'
import { useMachineDetailHierarchy } from '~/composables/useMachineDetailHierarchy'
import { useMachineDetailProducts } from '~/composables/useMachineDetailProducts'
import { useMachineDetailUpdates } from '~/composables/useMachineDetailUpdates'
import { downloadDocument as downloadDocumentHelper } from '~/shared/utils/documentDisplayUtils'

type AnyRecord = Record<string, unknown>

export function useMachineDetailData(machineId: string) {
  // External composables
  const {
    updateMachine: updateMachineApi,
    updateStructure: updateMachineStructure,
  } = useMachines()
  const { updateComposant: updateComposantApi } = useComposants()
  const { updatePiece: updatePieceApi } = usePieces()
  const { componentTypes, loadComponentTypes } = useComponentTypes()
  const { pieceTypes, loadPieceTypes } = usePieceTypes()
  const { upsertCustomFieldValue } = useCustomFields()
  const { get, patch: apiPatch } = useApi()
  const toast = useToast()
  const { constructeurs, loadConstructeurs } = useConstructeurs()
  const { sites, loadSites } = useSites()

  const {
    printModalOpen,
    printSelection,
    ensurePrintSelectionEntries: _ensurePrintEntries,
    setAllPrintSelection: _setAllPrint,
    openPrintModal: _openPrintModal,
    closePrintModal,
    handlePrintConfirm: _handlePrintConfirm,
  } = useMachinePrint()

  // Core state
  const loading = ref(true)
  const machine = ref<AnyRecord | null>(null)
  const productDocumentsMap = ref<Map<string, AnyRecord[]>>(new Map())
  const printAreaRef = ref<HTMLElement | null>(null)
  const saving = ref(false)

  // Constructeur links
  const { fetchLinks, syncLinks } = useConstructeurLinks()
  const constructeurLinks = ref<ConstructeurLinkEntry[]>([])
  const originalConstructeurLinks = ref<ConstructeurLinkEntry[]>([])

  // Machine fields
  const machineName = ref('')
  const machineReference = ref('')
  const machineSiteId = ref('')
  const machineConstructeurIds = ref<string[]>([])

  const machineConstructeurId = computed({
    get: () => machineConstructeurIds.value[0] || null,
    set: (value: string | null) => {
      machineConstructeurIds.value = value ? [value] : []
    },
  })

  const machineConstructeursDisplay = computed(() => {
    const ids = machineConstructeurIds.value
    if (!ids.length) return [] as any[]
    // Extract nested constructeur objects from link entries as candidate pool
    const linkConstructeurs = constructeurLinks.value
      .filter(l => l.constructeur && l.constructeur.id)
      .map(l => l.constructeur!) as any[]
    return resolveConstructeurs(
      ids,
      linkConstructeurs,
      constructeurs.value as any,
    ) as any[]
  })

  const machineConstructeurContact = computed(() =>
    machineConstructeursDisplay.value
      .map((c: any) => formatConstructeurContactSummary(c))
      .filter(Boolean)
      .join(' • '),
  )

  const hasMachineConstructeur = computed(
    () => machineConstructeursDisplay.value.length > 0,
  )

  // UI state
  const isEditMode = ref(false)
  const canSubmit = computed(() => {
    if (!machine.value) return false
    if (saving.value) return false
    if (!machineName.value.trim()) return false
    return true
  })

  const componentsCollapsed = ref(true)
  const collapseToggleToken = ref(0)

  const piecesCollapsed = ref(true)
  const pieceCollapseToggleToken = ref(0)

  // Sub-composables: Products (init first — hierarchy needs findProductById)
  // Products needs machineProductLinks from hierarchy, but hierarchy needs
  // findProductById from products. We break the cycle by passing a lazy
  // computed that reads from the hierarchy ref once it exists.
  const _machineProductLinksProxy = ref<AnyRecord[]>([])

  const {
    productInventory,
    productById,
    machineDirectProducts,
    findProductById,
    resolveProductReference,
    getProductDisplay,
    loadProducts,
  } = useMachineDetailProducts({
    machineProductLinks: _machineProductLinksProxy,
    productDocumentsMap,
    constructeurs,
  })

  // Sub-composables: Custom fields
  const {
    machineCustomFields,
    visibleMachineCustomFields,
    pendingContextFieldUpdates,
    transformCustomFields,
    transformComponentCustomFields,
    syncMachineCustomFields,
    setMachineCustomFieldValue,
    updateMachineCustomField,
    updatePieceCustomField,
    handleCustomFieldUpdate,
    queueContextFieldUpdate,
    clearPendingContextFieldUpdates,
    saveAllMachineCustomFields,
    saveAllContextCustomFields,
  } = useMachineDetailCustomFields({
    machine,
    isEditMode,
    constructeurs,
    resolveProductReference,
    getProductDisplay,
  })

  // Sub-composables: Hierarchy (includes structure link CRUD)
  const hierarchy = useMachineDetailHierarchy({
    machineId,
    machine,
    constructeurs,
    findProductById,
    transformComponentCustomFields,
    transformCustomFields,
    syncMachineCustomFields,
  })

  const {
    components,
    pieces,
    machineComponentLinks,
    machinePieceLinks,
    machineProductLinks,
    flattenedComponents,
    machinePieces,
    applyMachineLinks,
    reloadMachineStructure,
    addComponentLink,
    removeComponentLink,
    addPieceLink,
    removePieceLink,
    addProductLink,
    removeProductLink,
    addComponentLinkCategoryOnly,
    addPieceLinkCategoryOnly,
    addProductLinkCategoryOnly,
    fillEntityLink,
  } = hierarchy

  // Keep the product links proxy in sync with the hierarchy's machineProductLinks
  watch(machineProductLinks, (val) => { _machineProductLinksProxy.value = val }, { immediate: true })

  // Sub-composables: Documents
  const {
    machineDocumentFiles,
    machineDocumentsUploading,
    machineDocumentsLoaded,
    previewDocument,
    previewVisible,
    machineDocumentsList,
    refreshMachineDocuments,
    handleMachineFilesAdded,
    removeMachineDocument,
    openPreview,
    closePreview,
    loadProductDocuments: _loadProductDocuments,
  } = useMachineDetailDocuments({ machine })

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

  // Machine field methods
  const initMachineFields = () => {
    if (machine.value) {
      machineName.value = (machine.value.name as string) || ''
      machineReference.value = (machine.value.reference as string) || ''
      // Parse constructeur links from structure response
      const rawLinks = Array.isArray(machine.value.constructeurs) ? machine.value.constructeurs as any[] : []
      const parsed = parseConstructeurLinksFromApi(rawLinks)
      constructeurLinks.value = parsed
      originalConstructeurLinks.value = parsed.map(l => ({ ...l }))
      machineConstructeurIds.value = constructeurIdsFromLinks(parsed)
      machineSiteId.value = (machine.value.siteId as string) || (machine.value.site as AnyRecord)?.id as string || ''
    }
  }

  const getMachineFieldId = (fieldName: string): string => {
    return machine.value ? `machine-${fieldName}-${machine.value.id}` : `machine-${fieldName}`
  }

  // Product documents wrapper
  const loadProductDocuments = async () => {
    const map = await _loadProductDocuments(machineProductLinks.value)
    productDocumentsMap.value = map
  }

  // Update methods (delegated to useMachineDetailUpdates)
  const {
    updateMachineInfo,
    updateComponent,
    updatePieceFromComponent,
    updatePieceInfo,
    handleMachineConstructeurChange,
    editComponent,
    editPiece,
  } = useMachineDetailUpdates({
    machine,
    machineName,
    machineReference,
    machineSiteId,
    machineConstructeurIds,
    constructeurLinks,
    originalConstructeurLinks,
    machineDocumentsLoaded,
    machineComponentLinks,
    machinePieceLinks,
    machineProductLinks,
    applyMachineLinks,
    refreshMachineDocuments,
    transformComponentCustomFields,
    transformCustomFields,
    loadProductDocuments,
    upsertCustomFieldValue,
    updateMachineApi,
    updateComposantApi: updateComposantApi,
    updatePieceApi,
    apiPatch,
    toast,
    syncLinks,
  })

  // UI methods
  const toggleEditMode = () => {
    isEditMode.value = !isEditMode.value
    if (isEditMode.value && !machineDocumentsLoaded.value) {
      refreshMachineDocuments()
    }
  }

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

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

  const toggleAllPieces = () => {
    piecesCollapsed.value = !piecesCollapsed.value
    pieceCollapseToggleToken.value += 1
  }

  const submitEdition = async () => {
    if (!machine.value || saving.value) return
    saving.value = true

    try {
      // 1. Save machine info (name, reference, site, constructeurs)
      await updateMachineInfo()

      // 2. Save all custom field values
      await saveAllMachineCustomFields()

      // 3. Save contextual custom field values queued from piece/component inputs
      await saveAllContextCustomFields()

      // 4. Reload machine data to get fresh state
      await loadMachineData()

      // 5. Exit edit mode
      isEditMode.value = false
      toast.showSuccess('Machine mise à jour avec succès')
    } catch (error) {
      console.error('Erreur lors de la sauvegarde:', error)
      toast.showError('Erreur lors de la sauvegarde de la machine')
    } finally {
      saving.value = false
    }
  }

  const cancelEdition = () => {
    initMachineFields()
    syncMachineCustomFields()
    clearPendingContextFieldUpdates()
    constructeurLinks.value = originalConstructeurLinks.value.map(l => ({ ...l }))
    machineConstructeurIds.value = constructeurIdsFromLinks(constructeurLinks.value)
    isEditMode.value = false
  }

  // Print wrappers
  const ensurePrintSelectionEntries = () =>
    _ensurePrintEntries(components.value, machinePieces.value)
  const setAllPrintSelection = (value: boolean) =>
    _setAllPrint(value, components.value, machinePieces.value)
  const openPrintModal = () =>
    _openPrintModal(components.value, machinePieces.value)
  const handlePrintConfirm = () =>
    _handlePrintConfirm(
      machine.value as any,
      machineName.value,
      machineReference.value,
      machinePieces.value as any,
      components.value as any,
    )

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

      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 as AnyRecord[])?.length)
      syncMachineCustomFields()
      initMachineFields()

      // Start document loading early (independent of products/links)
      const documentPromise = !machineDocumentsLoaded.value
        ? refreshMachineDocuments()
        : Promise.resolve()

      // Load products in parallel — don't block hierarchy rendering
      const productsPromise = !(productInventory.value as AnyRecord[]).length
        ? loadProducts().catch((error: unknown) => {
            console.error('Erreur lors du chargement des produits:', error)
          })
        : Promise.resolve()

      await productsPromise
      const linksApplied = applyMachineLinks(machineResult.data)

      if (!linksApplied) {
        components.value = transformComponentCustomFields(machinePayload.components || [])
        pieces.value = transformCustomFields(machinePayload.pieces || [])
        machineProductLinks.value = Array.isArray(machinePayload.productLinks)
          ? machinePayload.productLinks
          : []
      }

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

      collapseAllComponents()

      // Load product documents in background
      loadProductDocuments().catch(() => {})

      // Wait for documents if still loading
      await documentPromise
    } catch (error) {
      console.error('Erreur lors du chargement des données:', error)
    } finally {
      loading.value = false
    }
  }

  const loadInitialData = (): Promise<unknown[]> => {
    return Promise.all([
      loadConstructeurs(),
      loadComponentTypes(),
      loadPieceTypes(),
      loadSites(),
    ])
  }

  // Watchers
  watch(() => (machine.value as AnyRecord)?.customFieldValues, () => syncMachineCustomFields(), { deep: true })
  watch(() => (machine.value as AnyRecord)?.customFields, () => syncMachineCustomFields(), { deep: true })
  watch(
    () => [components.value.length, machinePieces.value.length],
    () => ensurePrintSelectionEntries(),
    { immediate: true },
  )

  return {
    // State
    loading, machine, components, pieces, printAreaRef,
    machineComponentLinks, machinePieceLinks, machineProductLinks,

    // Machine fields
    machineName, machineReference, machineSiteId, machineConstructeurIds, machineConstructeurId,
    machineConstructeursDisplay, machineConstructeurContact, hasMachineConstructeur,
    constructeurLinks, originalConstructeurLinks,
    sites,

    // UI state
    machineDocumentFiles, machineDocumentsUploading, machineDocumentsLoaded,
    machineCustomFields, pendingContextFieldUpdates, previewDocument, previewVisible,
    isEditMode,
    componentsCollapsed, collapseToggleToken, piecesCollapsed, pieceCollapseToggleToken,

    // Computed
    componentTypeOptions, pieceTypeOptions,
    productInventory, productById, flattenedComponents, machinePieces,
    machineDirectProducts, machineDocumentsList, visibleMachineCustomFields,

    // Methods
    findProductById, resolveProductReference, getProductDisplay,
    initMachineFields, getMachineFieldId,
    syncMachineCustomFields, setMachineCustomFieldValue,
    updateMachineCustomField, updatePieceCustomField, handleCustomFieldUpdate,
    queueContextFieldUpdate, clearPendingContextFieldUpdates, saveAllContextCustomFields,
    refreshMachineDocuments, handleMachineFilesAdded, removeMachineDocument,
    openPreview, closePreview,
    updateMachineInfo, updateComponent, updatePieceFromComponent,
    updatePieceInfo, handleMachineConstructeurChange, editComponent, editPiece,
    toggleEditMode, toggleAllComponents, collapseAllComponents, toggleAllPieces,
    saving, canSubmit, submitEdition, cancelEdition,

    // Print
    printModalOpen, printSelection, ensurePrintSelectionEntries,
    setAllPrintSelection, openPrintModal, closePrintModal, handlePrintConfirm,

    // Loading & structure
    loadMachineData, loadInitialData,
    addComponentLink, removeComponentLink, addPieceLink, removePieceLink,
    addProductLink, removeProductLink, reloadMachineStructure,
    addComponentLinkCategoryOnly, addPieceLinkCategoryOnly,
    addProductLinkCategoryOnly, fillEntityLink,

    // External
    constructeurs, loadProducts, updateMachineStructure, toast,
    downloadDocument: downloadDocumentHelper,
  }
}
