export type SelectionEntry = {
  id: string
  path: string
  requirementLabel: string
  resolvedName: string
  quantity?: number
  slotId?: string
  _definition?: Record<string, any>
}

export type StructureSelectionResult = {
  pieces: SelectionEntry[]
  products: SelectionEntry[]
  components: SelectionEntry[]
}

type CatalogMap = Map<string, { name?: string, [key: string]: any }>

type LabelResolvers = {
  resolvePieceLabel: (definition: Record<string, any>) => string
  resolveProductLabel: (definition: Record<string, any>) => string
  resolveSubcomponentLabel: (definition: Record<string, any>) => string
}

const isNonEmptyString = (value: unknown): value is string =>
  typeof value === 'string' && value.trim().length > 0

export function collectStructureSelections(
  root: any,
  catalogs: {
    pieceCatalogMap: CatalogMap
    productCatalogMap: CatalogMap
    componentCatalogMap: CatalogMap
  },
  resolvers: LabelResolvers,
): StructureSelectionResult {
  const piecesSelected: SelectionEntry[] = []
  const productsSelected: SelectionEntry[] = []
  const componentsSelected: SelectionEntry[] = []

  if (!root || typeof root !== 'object') {
    return { pieces: piecesSelected, products: productsSelected, components: componentsSelected }
  }

  const visitNode = (node: any, fallbackPath = 'racine') => {
    if (!node || typeof node !== 'object') {
      return
    }

    const nodePath = isNonEmptyString(node.path) ? node.path : fallbackPath

    const nodePieces = Array.isArray(node.pieces) ? node.pieces : []
    nodePieces.forEach((entry: any, index: number) => {
      const selectedId = entry?.selectedPieceId
      if (!isNonEmptyString(selectedId)) {
        return
      }
      const definition = entry?.definition ?? entry
      const catalogPiece = catalogs.pieceCatalogMap.get(selectedId)
      piecesSelected.push({
        id: selectedId,
        path: isNonEmptyString(entry?.path) ? entry.path : `${nodePath}:piece-${index + 1}`,
        requirementLabel: resolvers.resolvePieceLabel(definition),
        resolvedName: catalogPiece?.name || selectedId,
        quantity: typeof definition?.quantity === 'number' ? definition.quantity : undefined,
        slotId: isNonEmptyString(entry?.slotId) ? entry.slotId : undefined,
        _definition: definition,
      })
    })

    const nodeProducts = Array.isArray(node.products) ? node.products : []
    nodeProducts.forEach((entry: any, index: number) => {
      const selectedId = entry?.selectedProductId
      if (!isNonEmptyString(selectedId)) {
        return
      }
      const definition = entry?.definition ?? entry
      const catalogProduct = catalogs.productCatalogMap.get(selectedId)
      productsSelected.push({
        id: selectedId,
        path: isNonEmptyString(entry?.path) ? entry.path : `${nodePath}:product-${index + 1}`,
        requirementLabel: resolvers.resolveProductLabel(definition),
        resolvedName: catalogProduct?.name || selectedId,
      })
    })

    const nodeChildren = Array.isArray(node.subcomponents)
      ? node.subcomponents
      : Array.isArray(node.subComponents)
        ? node.subComponents
        : []

    nodeChildren.forEach((child: any, index: number) => {
      const selectedId = child?.selectedComponentId
      if (isNonEmptyString(selectedId)) {
        const definition = child?.definition ?? child
        const catalogComponent = catalogs.componentCatalogMap.get(selectedId)
        componentsSelected.push({
          id: selectedId,
          path: isNonEmptyString(child?.path) ? child.path : `${nodePath}:subcomponent-${index + 1}`,
          requirementLabel: resolvers.resolveSubcomponentLabel(definition),
          resolvedName: catalogComponent?.name || selectedId,
        })
      }

      visitNode(child, isNonEmptyString(child?.path) ? child.path : `${nodePath}:subcomponent-${index + 1}`)
    })
  }

  visitNode(root, isNonEmptyString(root?.path) ? root.path : 'racine')

  return { pieces: piecesSelected, products: productsSelected, components: componentsSelected }
}
