import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useRouter } from '#imports'
import { usePieceTypes } from '~/composables/usePieceTypes'
import { usePieces } from '~/composables/usePieces'
import { useApi } from '~/composables/useApi'
import { useToast } from '~/composables/useToast'
import { useDocuments } from '~/composables/useDocuments'
import { useConstructeurs } from '~/composables/useConstructeurs'
import { useConstructeurLinks } from '~/composables/useConstructeurLinks'
import { useEntityHistory } from '~/composables/useEntityHistory'
import { extractRelationId } from '~/shared/apiRelations'
import { canPreviewDocument } from '~/utils/documentPreview'
import { formatPieceStructurePreview } from '~/shared/modelUtils'
import { uniqueConstructeurIds, constructeurIdsFromLinks } from '~/shared/constructeurUtils'
import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils'
import type { PieceModelStructure } from '~/shared/types/inventory'
import type { ModelType } from '~/services/modelTypes'
import {
  getStructureProducts,
  buildProductRequirementDescriptions,
  buildProductRequirementEntries,
  resizeProductSelections,
  applyProductSelection,
  collectNormalizedProductIds,
} from '~/shared/utils/pieceProductSelectionUtils'
import { getModelType } from '~/services/modelTypes'
import { useCustomFieldInputs, type CustomFieldInput } from '~/composables/useCustomFieldInputs'

interface PieceCatalogType extends ModelType {
  structure: PieceModelStructure | null
  customFields?: Array<Record<string, any>>
}

export function usePieceEdit(pieceId: string) {
  const { canEdit } = usePermissions()
  const router = useRouter()
  const { get } = useApi()
  const { pieceTypes, loadPieceTypes } = usePieceTypes()
  const { updatePiece } = usePieces()
  const toast = useToast()
  const { loadDocumentsByPiece, uploadDocuments, deleteDocument } = useDocuments()
  const { ensureConstructeurs } = useConstructeurs()
  const { fetchLinks, syncLinks } = useConstructeurLinks()
  const {
    history,
    loading: historyLoading,
    error: historyError,
    loadHistory,
  } = useEntityHistory('piece')

  const piece = ref<any | null>(null)
  const loading = ref(true)
  const saving = ref(false)
  const selectedFiles = ref<File[]>([])
  const uploadingDocuments = ref(false)
  const loadingDocuments = ref(false)
  const pieceDocuments = ref<any[]>([])
  const previewDocument = ref<any | null>(null)
  const previewVisible = ref(false)

  const historyFieldLabels: Record<string, string> = {
    name: 'Nom',
    reference: 'Référence',
    prix: 'Prix',
    typePiece: 'Catégorie',
    product: 'Produit lié',
    productIds: 'Produits liés',
    constructeurIds: 'Fournisseurs',
  }

  const selectedTypeId = ref<string>('')
  const pieceTypeDetails = ref<any | null>(null)
  const editionForm = reactive({
    name: '' as string,
    description: '' as string,
    reference: '' as string,
    constructeurIds: [] as string[],
    prix: '' as string,
  })
  const constructeurLinks = ref<ConstructeurLinkEntry[]>([])
  const originalConstructeurLinks = ref<ConstructeurLinkEntry[]>([])
  const constructeurIdsFromForm = computed(() => constructeurIdsFromLinks(constructeurLinks.value))
  const productSelections = ref<(string | null)[]>([])

  // Declared early so useCustomFieldInputs can reference it.
  // selectedType is defined later but is safely accessed inside a computed (lazy evaluation).
  const resolvedStructure = computed<PieceModelStructure | null>(() =>
    pieceTypeDetails.value?.structure ?? null,
  )

  const {
    fields: customFieldInputs,
    requiredFilled: requiredCustomFieldsFilled,
    saveAll: saveAllCustomFields,
    refresh: refreshCustomFieldInputs,
  } = useCustomFieldInputs({
    definitions: computed(() => resolvedStructure.value?.customFields ?? []),
    values: computed(() => piece.value?.customFieldValues ?? []),
    entityType: 'piece',
    entityId: computed(() => piece.value?.id ?? null),
    context: 'standalone',
    onValueCreated: (newValue) => {
      if (piece.value && Array.isArray(piece.value.customFieldValues)) {
        piece.value.customFieldValues.push(newValue)
      }
    },
  })

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

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

  const removeDocument = async (documentId: string | number | null | undefined) => {
    if (!documentId) {
      return
    }
    const result = await deleteDocument(documentId, { updateStore: false })
    if (result.success) {
      pieceDocuments.value = pieceDocuments.value.filter((doc) => doc.id !== documentId)
    }
  }

  const handleFilesAdded = async (files: File[]) => {
    if (!files?.length || !piece.value?.id) {
      return
    }
    uploadingDocuments.value = true
    try {
      const result = await uploadDocuments(
        {
          files,
          context: { pieceId: piece.value.id },
        },
        { updateStore: false },
      )
      if (result.success) {
        selectedFiles.value = []
        await refreshDocuments()
      }
    }
    finally {
      uploadingDocuments.value = false
    }
  }

  const refreshDocuments = async () => {
    if (!piece.value?.id) {
      pieceDocuments.value = []
      return
    }
    loadingDocuments.value = true
    try {
      const result = await loadDocumentsByPiece(piece.value.id, { updateStore: false })
      if (result.success) {
        pieceDocuments.value = Array.isArray(result.data) ? result.data : result.data ? [result.data] : []
      }
    }
    finally {
      loadingDocuments.value = false
    }
  }

  const pieceTypeList = computed<PieceCatalogType[]>(() => (pieceTypes.value || []) as PieceCatalogType[])

  const selectedType = computed(() => {
    if (!selectedTypeId.value) {
      return null
    }
    return pieceTypeList.value.find((type) => type.id === selectedTypeId.value) ?? null
  })

  const structureProducts = computed(() =>
    getStructureProducts(resolvedStructure.value),
  )

  const requiresProductSelection = computed(() => structureProducts.value.length > 0)

  const productRequirementDescriptions = computed(() =>
    buildProductRequirementDescriptions(structureProducts.value),
  )

  const ensureProductSelections = (count: number) => {
    productSelections.value = resizeProductSelections(productSelections.value, count)
  }

  let pendingProductIds: string[] = []

  const productRequirementEntries = computed(() =>
    buildProductRequirementEntries(structureProducts.value, 'piece-product-requirement'),
  )

  const productSelectionsFilled = computed(() => true)

  const setProductSelection = (index: number, value: string | null) => {
    productSelections.value = applyProductSelection(productSelections.value, index, value)
  }

  watch(structureProducts, (products) => {
    ensureProductSelections(products.length)
    if (!pendingProductIds.length || products.length === 0) {
      return
    }
    const next = Array.from(
      { length: products.length },
      (_, index) => pendingProductIds[index] ?? null,
    )
    productSelections.value = next
    pendingProductIds = []
  })

  const canSubmit = computed(() =>
    Boolean(
      canEdit.value
      && piece.value
      && editionForm.name
      && requiredCustomFieldsFilled.value
      && productSelectionsFilled.value
      && !saving.value,
    ),
  )

  const fetchPiece = async () => {
    if (!pieceId || typeof pieceId !== 'string') {
      piece.value = null
      pieceDocuments.value = []
      return
    }
    const result = await get(`/pieces/${pieceId}`)
    if (result.success) {
      piece.value = result.data
      pieceDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : []

      // The watcher on useCustomFieldInputs will auto-refresh when piece.value changes

      // Use cached type from loadPieceTypes() instead of separate getModelType() call
      loadPieceTypeDetailsFromCache(result.data)

      // History is non-blocking — template handles its own loading state
      loadHistory(result.data.id).catch(() => {})
    }
    else {
      piece.value = null
      pieceDocuments.value = []
    }
  }

  const loadPieceTypeDetailsFromCache = (currentPiece: any) => {
    const typeId = currentPiece?.typePieceId
      || extractRelationId(currentPiece?.typePiece)
      || ''
    if (!typeId) {
      pieceTypeDetails.value = null
      return
    }
    // Look up in the already-loaded pieceTypes cache (from loadPieceTypes in onMounted)
    const cachedType = (pieceTypes.value || []).find((t: any) => t.id === typeId) ?? null
    if (cachedType) {
      pieceTypeDetails.value = cachedType
      // useCustomFieldInputs auto-refreshes via its watcher on resolvedStructure
      return
    }
    // Fallback: fetch if not in cache (edge case)
    getModelType(typeId).then((type) => {
      if (type && typeof type === 'object') {
        pieceTypeDetails.value = type
        // useCustomFieldInputs auto-refreshes via its watcher on resolvedStructure
      }
    }).catch(() => {
      pieceTypeDetails.value = null
    })
  }

  let initialized = false

  watch(
    [piece, selectedType],
    ([currentPiece, _currentType]) => {
      if (!currentPiece || initialized) {
        return
      }

      const resolvedTypeId = currentPiece.typePieceId
        || extractRelationId(currentPiece.typePiece)
        || ''
      if (resolvedTypeId && !currentPiece.typePieceId) {
        currentPiece.typePieceId = resolvedTypeId
      }
      selectedTypeId.value = resolvedTypeId

      editionForm.name = currentPiece.name || ''
      editionForm.description = currentPiece.description || ''
      editionForm.reference = currentPiece.reference || ''
      // Load constructeur links
      fetchLinks('piece', pieceId).then((links) => {
        constructeurLinks.value = links
        originalConstructeurLinks.value = links.map(l => ({ ...l }))
        editionForm.constructeurIds = constructeurIdsFromLinks(links)
        if (editionForm.constructeurIds.length) {
          void ensureConstructeurs(editionForm.constructeurIds)
        }
      })
      editionForm.prix = currentPiece.prix !== null && currentPiece.prix !== undefined ? String(currentPiece.prix) : ''

      const existingProductIds = Array.isArray(currentPiece.productIds) && currentPiece.productIds.length
        ? currentPiece.productIds.map((id: unknown) => String(id))
        : currentPiece.product?.id || currentPiece.productId
          ? [String(currentPiece.product?.id || currentPiece.productId)]
          : []
      pendingProductIds = existingProductIds
      ensureProductSelections(structureProducts.value.length)
      if (existingProductIds.length && structureProducts.value.length) {
        const next = Array.from(
          { length: structureProducts.value.length },
          (_, index) => existingProductIds[index] ?? null,
        )
        productSelections.value = next
        pendingProductIds = []
      }

      // useCustomFieldInputs auto-refreshes via its watcher on definitions + values

      initialized = true
    },
    { immediate: true },
  )

  // useCustomFieldInputs auto-refreshes when selectedType changes (via resolvedStructure)

  watch(resolvedStructure, () => {
    if (!piece.value) {
      return
    }
    ensureProductSelections(structureProducts.value.length)
    // useCustomFieldInputs auto-refreshes via its watcher on definitions
  })

  const submitEdition = async () => {
    if (!piece.value) {
      return
    }

    const rawPrice = typeof editionForm.prix === 'string'
      ? editionForm.prix.trim()
      : editionForm.prix === null || editionForm.prix === undefined
        ? ''
        : String(editionForm.prix).trim()

    const payload: Record<string, any> = {
      name: editionForm.name.trim(),
      description: editionForm.description.trim() || null,
    }

    const reference = editionForm.reference.trim()
    payload.reference = reference ? reference : null

    const normalizedProductIds = collectNormalizedProductIds(
      productRequirementEntries.value,
      productSelections.value,
    )

    payload.productIds = normalizedProductIds
    payload.productId = normalizedProductIds[0] || null

    if (rawPrice) {
      const parsed = Number(rawPrice)
      if (!Number.isNaN(parsed)) {
        payload.prix = String(parsed)
      }
    }
    else {
      payload.prix = null
    }

    saving.value = true
    try {
      const result = await updatePiece(piece.value.id, payload)
      if (result.success && result.data) {
        const failedFields = await saveAllCustomFields()
        if (failedFields.length) {
          toast.showError(`Erreur sur les champs : ${failedFields.join(', ')}`)
        }
        await syncLinks('piece', piece.value.id, originalConstructeurLinks.value, constructeurLinks.value)
        originalConstructeurLinks.value = constructeurLinks.value.map(l => ({ ...l }))
        toast.showSuccess('Pièce mise à jour avec succès.')
      }
    }
    catch (error: any) {
      toast.showError(error?.message || 'Erreur lors de la mise à jour de la pièce')
    }
    finally {
      saving.value = false
    }
  }

  onMounted(async () => {
    await Promise.allSettled([loadPieceTypes(), fetchPiece()])
    loading.value = false
  })

  return {
    // State
    piece,
    loading,
    saving,
    selectedFiles,
    uploadingDocuments,
    loadingDocuments,
    pieceDocuments,
    previewDocument,
    previewVisible,
    selectedTypeId,
    editionForm,
    constructeurLinks,
    originalConstructeurLinks,
    constructeurIdsFromForm,
    productSelections,
    customFieldInputs,
    requiredCustomFieldsFilled,
    canEdit,

    // Computed
    pieceTypeList,
    selectedType,
    resolvedStructure,
    structureProducts,
    productRequirementDescriptions,
    productRequirementEntries,
    canSubmit,
    historyFieldLabels,

    // History
    history,
    historyLoading,
    historyError,

    // Methods
    openPreview,
    closePreview,
    removeDocument,
    handleFilesAdded,
    setProductSelection,
    submitEdition,
    fetchPiece,
    formatPieceStructurePreview,
  }
}
