/**
 * Machine detail — custom field management sub-composable.
 *
 * Handles custom field resolution, display filtering, sync and updates
 * for machines, components and pieces.
 */

import { ref, computed } from 'vue'
import { useCustomFields } from '~/composables/useCustomFields'
import { useToast } from '~/composables/useToast'
import {
  mergeDefinitionsWithValues,
  filterByContext,
  hasDisplayableValue,
  type CustomFieldInput,
} from '~/shared/utils/customFields'
import {
  resolveConstructeurs,
  uniqueConstructeurIds,
} from '~/shared/constructeurUtils'

type AnyRecord = Record<string, unknown>

interface MachineDetailCustomFieldsDeps {
  machine: Ref<AnyRecord | null>
  isEditMode: Ref<boolean>
  constructeurs: Ref<unknown[]>
  resolveProductReference: (source: AnyRecord) => { product: unknown; productId: string | null }
  getProductDisplay: (source: AnyRecord) => unknown
}

export function useMachineDetailCustomFields(deps: MachineDetailCustomFieldsDeps) {
  const { machine, isEditMode, constructeurs, resolveProductReference, getProductDisplay } = deps
  const {
    upsertCustomFieldValue,
    updateCustomFieldValue: updateCustomFieldValueApi,
  } = useCustomFields()
  const toast = useToast()

  // ---------------------------------------------------------------------------
  // State
  // ---------------------------------------------------------------------------

  const machineCustomFields = ref<AnyRecord[]>([])
  const pendingContextFieldUpdates = ref<AnyRecord[]>([])

  // ---------------------------------------------------------------------------
  // Computed
  // ---------------------------------------------------------------------------

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

  // ---------------------------------------------------------------------------
  // Transform helpers
  // ---------------------------------------------------------------------------

  const transformCustomFields = (piecesData: AnyRecord[]): AnyRecord[] => {
    return (piecesData || []).map((piece) => {
      const typePiece = (piece.typePiece as AnyRecord) || {}

      const customFields = filterByContext(
        mergeDefinitionsWithValues(
          typePiece.customFields ?? (piece.typePiece as AnyRecord)?.customFields ?? [],
          piece.customFieldValues ?? [],
        ),
        'standalone',
      )

      const constructeurIds = uniqueConstructeurIds(
        piece.constructeurs,
        piece.constructeurIds,
        piece.constructeurId,
        piece.constructeur,
        (piece.originalPiece as AnyRecord)?.constructeurs,
        (piece.originalPiece as AnyRecord)?.constructeurIds,
        (piece.originalPiece as AnyRecord)?.constructeurId,
        (piece.originalPiece as AnyRecord)?.constructeur,
      )

      const { product: resolvedProduct, productId: resolvedProductId } =
        resolveProductReference(piece)

      const constructeursList = resolveConstructeurs(
        constructeurIds,
        Array.isArray(piece.constructeurs) ? (piece.constructeurs as any[]) : [],
        piece.constructeur ? [piece.constructeur as any] : [],
        Array.isArray((piece.originalPiece as AnyRecord)?.constructeurs)
          ? ((piece.originalPiece as AnyRecord).constructeurs as any[])
          : [],
        (piece.originalPiece as AnyRecord)?.constructeur
          ? [(piece.originalPiece as AnyRecord).constructeur as any]
          : [],
        constructeurs.value as any,
      ) as any[]

      const normalizedPiece = {
        ...piece,
        product: resolvedProduct || piece.product || null,
        productId: resolvedProductId || piece.productId || (piece.product as AnyRecord)?.id || null,
      }
      const productDisplay = getProductDisplay(normalizedPiece)

      return {
        ...normalizedPiece,
        customFields: customFields.filter((f: any) => !f.machineContextOnly && !f.customField?.machineContextOnly),
        contextCustomFields: piece.contextCustomFields ?? [],
        contextCustomFieldValues: piece.contextCustomFieldValues ?? [],
        documents: piece.documents || [],
        constructeurs: constructeursList,
        constructeur: constructeursList[0] || piece.constructeur || null,
        constructeurIds,
        constructeurId: constructeurIds[0] || null,
        typePieceId:
          piece.typePieceId ||
          (piece.typePiece as AnyRecord)?.id ||
          null,
        __productDisplay: productDisplay,
      }
    })
  }

  const transformComponentCustomFields = (componentsData: AnyRecord[]): AnyRecord[] => {
    return (componentsData || []).map((component) => {
      const type = (component.typeComposant as AnyRecord) || {}
      const actualComponent = (component.originalComposant as AnyRecord) || component

      const customFields = filterByContext(
        mergeDefinitionsWithValues(
          type.customFields ?? [],
          component.customFieldValues ?? actualComponent?.customFieldValues ?? [],
        ),
        'standalone',
      )

      const piecesTransformed = component.pieces
        ? transformCustomFields(component.pieces as AnyRecord[]).map((p) => ({
            ...p,
            parentComponentName: component.name,
          }))
        : []

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

      const constructeurIds = uniqueConstructeurIds(
        component.constructeurs,
        component.constructeurIds,
        component.constructeurId,
        component.constructeur,
        actualComponent?.constructeurs,
        actualComponent?.constructeurIds,
        actualComponent?.constructeurId,
        actualComponent?.constructeur,
      )

      const constructeursList = resolveConstructeurs(
        constructeurIds,
        Array.isArray(component.constructeurs) ? (component.constructeurs as any[]) : [],
        component.constructeur ? [component.constructeur as any] : [],
        Array.isArray(actualComponent?.constructeurs)
          ? (actualComponent.constructeurs as any[])
          : [],
        actualComponent?.constructeur ? [actualComponent.constructeur as any] : [],
        constructeurs.value as any,
      ) as any[]

      const { product: resolvedProduct, productId: resolvedProductId } =
        resolveProductReference(component)
      const normalizedComponent = {
        ...component,
        product: resolvedProduct || component.product || null,
        productId:
          resolvedProductId || component.productId || (component.product as AnyRecord)?.id || null,
      }
      const productDisplay = getProductDisplay(normalizedComponent)

      return {
        ...normalizedComponent,
        customFields: customFields.filter((f: any) => !f.machineContextOnly && !f.customField?.machineContextOnly),
        contextCustomFields: component.contextCustomFields ?? [],
        contextCustomFieldValues: component.contextCustomFieldValues ?? [],
        pieces: piecesTransformed,
        subComponents,
        documents: component.documents || [],
        constructeurs: constructeursList,
        constructeur: constructeursList[0] || component.constructeur || null,
        constructeurIds,
        constructeurId: constructeurIds[0] || null,
        typeComposantId:
          component.typeComposantId ||
          (component.typeComposant as AnyRecord)?.id ||
          null,
        __productDisplay: productDisplay,
      }
    })
  }

  // ---------------------------------------------------------------------------
  // Machine custom field methods
  // ---------------------------------------------------------------------------

  const syncMachineCustomFields = () => {
    if (!machine.value) {
      machineCustomFields.value = []
      return
    }
    const merged = mergeDefinitionsWithValues(
      machine.value?.customFields ?? [],
      machine.value?.customFieldValues ?? [],
    )
    machineCustomFields.value = merged.map(f => ({ ...f, readOnly: false }))
  }

  const setMachineCustomFieldValue = (field: AnyRecord, value: unknown) => {
    if (!field) return
    field.value = value
    if (field.customFieldValueId && (machine.value as AnyRecord)?.customFieldValues) {
      const stored = ((machine.value as AnyRecord).customFieldValues as AnyRecord[]).find(
        (fv) => fv.id === field.customFieldValueId,
      )
      if (stored) stored.value = value
    }
  }

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

    const customFieldId = (field.customFieldId ?? field.id) as string | undefined
    const customFieldValueId = field.customFieldValueId as string | undefined
    const fieldLabel = (field.name as string) || 'Champ personnalisé'

    try {
      if (customFieldValueId) {
        const result: any = await updateCustomFieldValueApi(customFieldValueId as string, {
          value: field.value ?? '',
        } as any)
        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: any = await upsertCustomFieldValue(
        customFieldId as string,
        'machine',
        machine.value.id as string,
        field.value ?? '',
      )
      if (result.success) {
        const createdValue = result.data as AnyRecord
        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 as AnyRecord[]).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: AnyRecord) => {
    try {
      const result: any = await upsertCustomFieldValue(
        fieldUpdate.fieldId as string,
        'piece',
        fieldUpdate.pieceId as string,
        fieldUpdate.value,
      )
      if (result.success) {
        toast.showSuccess('Champ personnalisé mis à jour avec succès')
      } else {
        toast.showError('Erreur lors de la mise à jour du champ personnalisé')
      }
    } catch (error) {
      toast.showError('Erreur lors de la mise à jour du champ personnalisé')
      console.error('Erreur lors de la mise à jour du champ personnalisé:', error)
    }
  }

  const handleCustomFieldUpdate = async (fieldUpdate: AnyRecord) => {
    if (fieldUpdate?.entityType && fieldUpdate?.entityId) {
      queueContextFieldUpdate(fieldUpdate)
      return
    }

    await updatePieceCustomField(fieldUpdate)
  }

  const queueContextFieldUpdate = (fieldUpdate: AnyRecord) => {
    const entityType = fieldUpdate.entityType as string | undefined
    const entityId = fieldUpdate.entityId as string | undefined
    const fieldId = fieldUpdate.fieldId as string | undefined
    const customFieldValueId = fieldUpdate.customFieldValueId as string | undefined

    if (!entityType || !entityId || (!fieldId && !customFieldValueId)) return

    const nextUpdate = {
      entityType,
      entityId,
      fieldId,
      customFieldValueId,
      value: fieldUpdate.value ?? '',
      fieldName: fieldUpdate.fieldName ?? 'Champ contextuel',
    }

    const existingIndex = pendingContextFieldUpdates.value.findIndex(
      (item) =>
        item.entityType === entityType &&
        item.entityId === entityId &&
        item.fieldId === fieldId &&
        item.customFieldValueId === customFieldValueId,
    )

    if (existingIndex >= 0) {
      pendingContextFieldUpdates.value[existingIndex] = nextUpdate
      return
    }

    pendingContextFieldUpdates.value.push(nextUpdate)
  }

  const clearPendingContextFieldUpdates = () => {
    pendingContextFieldUpdates.value = []
  }

  const saveAllContextCustomFields = async () => {
    const updates = pendingContextFieldUpdates.value.slice()
    if (!updates.length) return

    try {
      for (const update of updates) {
        if (update.customFieldValueId) {
          await updateCustomFieldValueApi(update.customFieldValueId as string, {
            value: update.value ?? '',
          } as any)
          continue
        }

        if (!update.fieldId) {
          continue
        }

        await upsertCustomFieldValue(
          update.fieldId as string,
          update.entityType as string,
          update.entityId as string,
          update.value ?? '',
        )
      }
      clearPendingContextFieldUpdates()
    } catch (error) {
      console.error('Erreur lors de la sauvegarde batch des champs contextuels:', error)
      throw error
    }
  }

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

    const fields = Array.isArray(machineCustomFields.value) ? machineCustomFields.value : []
    const fieldsToSave = fields.filter(
      (field) => field.value !== undefined && field.value !== null && String(field.value).trim() !== '',
    )

    for (const field of fieldsToSave) {
      const customFieldId = (field.customFieldId ?? field.id) as string | undefined
      const customFieldValueId = field.customFieldValueId as string | undefined

      try {
        if (customFieldValueId) {
          await updateCustomFieldValueApi(customFieldValueId as string, {
            value: field.value ?? '',
          } as any)
        } else if (customFieldId) {
          const result: any = await upsertCustomFieldValue(
            customFieldId as string,
            'machine',
            machine.value.id as string,
            field.value ?? '',
          )
          if (result.success) {
            const createdValue = result.data as AnyRecord
            if (createdValue?.id) {
              field.customFieldValueId = createdValue.id
              if (!createdValue.customField) {
                createdValue.customField = {
                  id: customFieldId,
                  name: field.name,
                  type: field.type,
                  required: field.required,
                  options: field.options,
                }
              }
              const existingValues = Array.isArray(machine.value.customFieldValues)
                ? (machine.value.customFieldValues as AnyRecord[]).filter(
                    (item) => item.id !== createdValue.id,
                  )
                : []
              machine.value.customFieldValues = [...existingValues, createdValue]
            }
          }
        }
      } catch (error) {
        console.error('Erreur lors de la sauvegarde du champ personnalisé:', error)
        throw error
      }
    }
  }

  return {
    // State
    machineCustomFields,
    pendingContextFieldUpdates,

    // Computed
    visibleMachineCustomFields,

    // Transform functions
    transformCustomFields,
    transformComponentCustomFields,

    // Methods
    syncMachineCustomFields,
    setMachineCustomFieldValue,
    updateMachineCustomField,
    updatePieceCustomField,
    handleCustomFieldUpdate,
    queueContextFieldUpdate,
    clearPendingContextFieldUpdates,
    saveAllMachineCustomFields,
    saveAllContextCustomFields,
  }
}
