import { computed, watch } from 'vue'
import type { ComponentModelPiece, ComponentModelProduct, ComponentModelStructureNode } from '~/shared/types/inventory'
import { useStructureNodeCrud } from '~/composables/useStructureNodeCrud'

export type ModelTypeOption = {
  id: string
  name: string
  code?: string | null
}

export type EditableStructureNode = ComponentModelStructureNode & {
  customFields?: any[]
  pieces?: ComponentModelPiece[]
  products?: ComponentModelProduct[]
}

export interface StructureNodeLogicDeps {
  node: EditableStructureNode
  depth: number
  componentTypes: ModelTypeOption[]
  pieceTypes: ModelTypeOption[]
  productTypes: ModelTypeOption[]
  isRoot: boolean
  lockType: boolean
  lockedTypeLabel: string
  allowSubcomponents: boolean
  maxSubcomponentDepth: number
  isLocked: boolean
}

export function useStructureNodeLogic(props: StructureNodeLogicDeps) {
  // --- Computed props ---
  const isLocked = computed(() => props.isLocked === true)

  const componentTypes = computed(() => props.componentTypes ?? [])
  const pieceTypes = computed(() => props.pieceTypes ?? [])
  const productTypes = computed(() => props.productTypes ?? [])
  const allowSubcomponents = computed(() => props.allowSubcomponents !== false)
  const maxSubcomponentDepth = computed(() =>
    typeof props.maxSubcomponentDepth === 'number' ? props.maxSubcomponentDepth : Infinity,
  )
  const currentDepth = computed(() => Math.max(0, props.depth ?? 0))
  const canManageSubcomponents = computed(
    () => allowSubcomponents.value && currentDepth.value < maxSubcomponentDepth.value,
  )
  const childAllowSubcomponents = computed(
    () => allowSubcomponents.value && currentDepth.value + 1 < maxSubcomponentDepth.value,
  )
  const hasSubcomponents = computed(
    () => Array.isArray(props.node?.subcomponents) && props.node.subcomponents.length > 0,
  )

  const depthClasses = ['', 'ml-4', 'ml-8', 'ml-12', 'ml-16', 'ml-20']
  const containerClass = computed(() => {
    const level = currentDepth.value
    const index = Math.min(level, depthClasses.length - 1)
    return level === 0 ? 'space-y-4' : `${depthClasses[index]} space-y-4`
  })

  const headingClass = computed(() => (props.isRoot ? 'text-sm font-semibold' : 'text-xs font-semibold'))

  // --- Type maps ---
  const formatModelTypeOption = (type: ModelTypeOption | undefined | null) =>
    type?.name ?? ''

  const componentTypeMap = computed(() => {
    const map = new Map<string, ModelTypeOption>()
    componentTypes.value.forEach((type) => {
      if (type && typeof type.id === 'string') {
        map.set(type.id, type)
      }
    })
    return map
  })

  const componentTypeCodeMap = computed(() => {
    const map = new Map<string, ModelTypeOption>()
    componentTypes.value.forEach((type) => {
      const code = typeof type?.code === 'string' ? type.code.trim() : ''
      if (code) {
        map.set(code, type)
      }
    })
    return map
  })

  const pieceTypeMap = computed(() => {
    const map = new Map<string, ModelTypeOption>()
    pieceTypes.value.forEach((type) => {
      if (type && typeof type.id === 'string') {
        map.set(type.id, type)
      }
    })
    return map
  })

  const productTypeMap = computed(() => {
    const map = new Map<string, ModelTypeOption>()
    productTypes.value.forEach((type) => {
      if (type && typeof type.id === 'string') {
        map.set(type.id, type)
      }
    })
    return map
  })

  // --- Label getters ---
  const getComponentTypeLabel = (id?: string) => {
    if (!id) return ''
    return formatModelTypeOption(componentTypeMap.value.get(id))
  }

  const getPieceTypeLabel = (id?: string) => {
    if (!id) return ''
    return formatModelTypeOption(pieceTypeMap.value.get(id))
  }

  const formatComponentTypeOption = (type: ModelTypeOption | undefined | null) =>
    formatModelTypeOption(type)

  const formatPieceTypeOption = (type: ModelTypeOption | undefined | null) =>
    formatModelTypeOption(type)

  const formatProductTypeOption = (type: ModelTypeOption | undefined | null) =>
    formatModelTypeOption(type)

  const lockedTypeDisplay = computed(() => {
    if (props.lockedTypeLabel) {
      return props.lockedTypeLabel
    }
    return getComponentTypeLabel(props.node?.typeComposantId) || 'Famille non définie'
  })

  // --- Sync functions ---
  const syncComponentType = (component: EditableStructureNode) => {
    if (!component) {
      return
    }
    if (props.isRoot) {
      component.typeComposantId = ''
      component.typeComposantLabel = ''
      component.familyCode = ''
      if (component.alias) {
        component.alias = ''
      }
      return
    }
    const id = typeof component.typeComposantId === 'string'
      ? component.typeComposantId
      : ''

    if (!id) {
      const code =
        typeof component.familyCode === 'string' && component.familyCode
          ? component.familyCode
          : ''
      if (code) {
        const codeMatch = componentTypeCodeMap.value.get(code)
        if (codeMatch?.id) {
          component.typeComposantId = codeMatch.id
          component.typeComposantLabel = formatModelTypeOption(codeMatch)
          component.familyCode = codeMatch.code ?? component.familyCode
          if (!component.alias || component.alias === '' || component.alias === lockedTypeDisplay.value) {
            component.alias = codeMatch.name || component.typeComposantLabel
          }
          return
        }
      }
      component.typeComposantLabel = ''
      component.familyCode = ''
      return
    }

    const option = componentTypeMap.value.get(id)
    if (!option) {
      component.typeComposantLabel = ''
      component.familyCode = ''
      return
    }

    component.typeComposantLabel = formatModelTypeOption(option)
    component.familyCode = option.code ?? component.familyCode
    if (!component.alias || component.alias === '' || component.alias === lockedTypeDisplay.value) {
      component.alias = option.name || component.typeComposantLabel
    }
  }

  const updatePieceTypeLabel = (piece: ComponentModelPiece & Record<string, any>) => {
    if (!piece) return

    if (piece.typePieceId) {
      const option = pieceTypeMap.value.get(piece.typePieceId)
      if (option) {
        piece.typePieceLabel = formatPieceTypeOption(option)
        return
      }
    }

    if (piece.typePieceLabel) {
      const normalized = piece.typePieceLabel.trim().toLowerCase()
      if (normalized) {
        const match = pieceTypes.value.find((type) => {
          const formatted = formatPieceTypeOption(type).toLowerCase()
          const name = (type?.name ?? '').toLowerCase()
          const code = (type?.code ?? '').toLowerCase()
          return formatted === normalized || name === normalized || (!!code && code === normalized)
        })
        if (match) {
          piece.typePieceId = match.id
          piece.typePieceLabel = formatPieceTypeOption(match)
          return
        }
      }
    }
  }

  const updateProductTypeLabel = (product: ComponentModelProduct & Record<string, any>) => {
    if (!product) return

    if (product.typeProductId) {
      const option = productTypeMap.value.get(product.typeProductId)
      if (option) {
        product.typeProductLabel = formatProductTypeOption(option)
        product.familyCode = option.code ?? product.familyCode ?? ''
        return
      }
    }

    if (product.typeProductLabel) {
      const normalized = product.typeProductLabel.trim().toLowerCase()
      if (normalized) {
        const match = productTypes.value.find((type) => {
          const formatted = formatProductTypeOption(type).toLowerCase()
          const name = (type?.name ?? '').toLowerCase()
          const code = (type?.code ?? '').toLowerCase()
          return formatted === normalized || name === normalized || (!!code && code === normalized)
        })
        if (match) {
          product.typeProductId = match.id
          product.typeProductLabel = formatProductTypeOption(match)
          product.familyCode = match.code ?? product.familyCode ?? ''
          return
        }
      }
    }
  }

  const syncPieceLabels = (pieces?: any[]) => {
    if (!Array.isArray(pieces)) {
      return
    }
    pieces.forEach((piece) => {
      updatePieceTypeLabel(piece)
    })
  }

  const syncProductLabels = (products?: any[]) => {
    if (!Array.isArray(products)) {
      return
    }
    products.forEach((product) => {
      updateProductTypeLabel(product)
    })
  }

  // --- Handler functions ---
  const handleComponentTypeSelect = (component: any) => {
    syncComponentType(component)
  }

  const handlePieceTypeSelect = (piece: ComponentModelPiece & Record<string, any>) => {
    if (!piece) {
      return
    }
    const id = typeof piece.typePieceId === 'string' ? piece.typePieceId : ''
    if (!id) {
      piece.typePieceLabel = ''
      return
    }
    const option = pieceTypeMap.value.get(id)
    if (!option) {
      piece.typePieceId = ''
      piece.typePieceLabel = ''
      return
    }
    piece.typePieceLabel = formatPieceTypeOption(option)
  }

  const handleProductTypeSelect = (product: ComponentModelProduct & Record<string, any>) => {
    if (!product) {
      return
    }
    const id = typeof product.typeProductId === 'string' ? product.typeProductId : ''
    if (!id) {
      product.typeProductLabel = ''
      return
    }
    const option = productTypeMap.value.get(id)
    if (!option) {
      product.typeProductId = ''
      product.typeProductLabel = ''
      return
    }
    product.typeProductLabel = formatProductTypeOption(option)
    product.familyCode = option.code ?? product.familyCode ?? ''
  }

  // --- CRUD & Lock (delegated to useStructureNodeCrud) ---
  const crud = useStructureNodeCrud({
    node: props.node,
    canManageSubcomponents: () => canManageSubcomponents.value,
  })

  // --- Watchers ---
  watch(
    canManageSubcomponents,
    (allowed) => {
      if (!allowed && Array.isArray(props.node.subcomponents) && props.node.subcomponents.length) {
        props.node.subcomponents.splice(0, props.node.subcomponents.length)
      }
    },
    { immediate: true },
  )

  watch(componentTypes, () => {
    syncComponentType(props.node)
  }, { deep: true, immediate: true })

  watch(
    () => props.node.typeComposantId,
    () => {
      syncComponentType(props.node)
    },
  )

  watch(pieceTypes, () => {
    syncPieceLabels(props.node?.pieces)
  }, { deep: true, immediate: true })

  watch(
    () => props.node.pieces,
    (value) => {
      syncPieceLabels(value)
    },
    { deep: true },
  )

  watch(productTypes, () => {
    syncProductLabels(props.node?.products)
  }, { deep: true, immediate: true })

  watch(
    () => props.node.products,
    (value) => {
      syncProductLabels(value)
    },
    { deep: true },
  )

  watch(
    () => props.node.customFields,
    (value) => {
      if (!Array.isArray(value)) {
        return
      }
      value.sort((a: any, b: any) => {
        const left = typeof a?.orderIndex === 'number' ? a.orderIndex : 0
        const right = typeof b?.orderIndex === 'number' ? b.orderIndex : 0
        return left - right
      })
      crud.reindexCustomFields()
    },
    { deep: true },
  )

  watch(
    () => [props.lockedTypeLabel, props.lockType],
    () => {
      if (props.lockType && props.isRoot) {
        const label = props.lockedTypeLabel || lockedTypeDisplay.value
        props.node.typeComposantLabel = label
        if (label && (!props.node.alias || props.node.alias === lockedTypeDisplay.value)) {
          props.node.alias = label
        }
        if (props.node.typeComposantId) {
          const option = componentTypeMap.value.get(props.node.typeComposantId)
          props.node.familyCode = option?.code ?? props.node.familyCode
        }
      }
    },
    { immediate: true },
  )

  return {
    // Computed state
    isLocked,
    componentTypes,
    pieceTypes,
    productTypes,
    canManageSubcomponents,
    childAllowSubcomponents,
    hasSubcomponents,
    containerClass,
    headingClass,
    lockedTypeDisplay,
    // Label getters & formatters
    getComponentTypeLabel,
    getPieceTypeLabel,
    formatComponentTypeOption,
    formatPieceTypeOption,
    formatProductTypeOption,
    // Handlers
    handleComponentTypeSelect,
    handlePieceTypeSelect,
    handleProductTypeSelect,
    // CRUD
    addCustomField: crud.addCustomField,
    removeCustomField: crud.removeCustomField,
    addPiece: crud.addPiece,
    removePiece: crud.removePiece,
    addProduct: crud.addProduct,
    removeProduct: crud.removeProduct,
    addSubComponent: crud.addSubComponent,
    removeSubComponent: crud.removeSubComponent,
    // Drag reorder — custom fields
    onCustomFieldDragStart: crud.onCustomFieldDragStart,
    onCustomFieldDragEnter: crud.onCustomFieldDragEnter,
    onCustomFieldDrop: crud.onCustomFieldDrop,
    onCustomFieldDragEnd: crud.onCustomFieldDragEnd,
    customFieldReorderClass: crud.customFieldReorderClass,
    // Drag reorder — pieces
    onPieceDragStart: crud.onPieceDragStart,
    onPieceDragEnter: crud.onPieceDragEnter,
    onPieceDragOver: crud.onPieceDragOver,
    onPieceDrop: crud.onPieceDrop,
    onPieceDragEnd: crud.onPieceDragEnd,
    pieceReorderClass: crud.pieceReorderClass,
    // Drag reorder — products
    onProductDragStart: crud.onProductDragStart,
    onProductDragEnter: crud.onProductDragEnter,
    onProductDragOver: crud.onProductDragOver,
    onProductDrop: crud.onProductDrop,
    onProductDragEnd: crud.onProductDragEnd,
    productReorderClass: crud.productReorderClass,
    // Drag reorder — subcomponents
    onSubcomponentDragStart: crud.onSubcomponentDragStart,
    onSubcomponentDragEnter: crud.onSubcomponentDragEnter,
    onSubcomponentDragOver: crud.onSubcomponentDragOver,
    onSubcomponentDrop: crud.onSubcomponentDrop,
    onSubcomponentDragEnd: crud.onSubcomponentDragEnd,
    subcomponentReorderClass: crud.subcomponentReorderClass,
  }
}
