/**
 * Pure helper functions for building, validating and serializing
 * component structure assignment trees.
 *
 * Extracted from useComponentCreate composable to keep file sizes manageable.
 */

import type { StructureAssignmentNode } from '~/components/ComponentStructureAssignmentNode.vue'
import type {
  ComponentModelPiece,
  ComponentModelProduct,
  ComponentModelStructure,
  ComponentModelStructureNode,
} from '~/shared/types/inventory'

// ---------------------------------------------------------------------------
// Extraction helpers
// ---------------------------------------------------------------------------

export function extractSubcomponents(
  definition: ComponentModelStructure | ComponentModelStructureNode | null | undefined,
): ComponentModelStructureNode[] {
  if (!definition || typeof definition !== 'object') {
    return []
  }
  const raw = Array.isArray((definition as any).subcomponents)
    ? (definition as any).subcomponents
    : Array.isArray((definition as any).subComponents)
      ? (definition as any).subComponents
      : []
  return raw.filter(
    (item: unknown): item is ComponentModelStructureNode =>
      !!item && typeof item === 'object',
  )
}

export function extractPiecesFromNode(
  definition: ComponentModelStructure | ComponentModelStructureNode | null | undefined,
): ComponentModelPiece[] {
  if (!definition || typeof definition !== 'object') {
    return []
  }
  const raw = Array.isArray((definition as any).pieces)
    ? (definition as any).pieces
    : []
  return raw.filter(
    (item: unknown): item is ComponentModelPiece =>
      !!item && typeof item === 'object',
  )
}

export function extractProductsFromNode(
  definition: ComponentModelStructure | ComponentModelStructureNode | null | undefined,
): ComponentModelProduct[] {
  if (!definition || typeof definition !== 'object') {
    return []
  }
  const raw = Array.isArray((definition as any).products)
    ? (definition as any).products
    : []
  return raw.filter(
    (item: unknown): item is ComponentModelProduct =>
      !!item && typeof item === 'object',
  )
}

// ---------------------------------------------------------------------------
// Assignment tree building
// ---------------------------------------------------------------------------

export function buildAssignmentNode(
  definition: ComponentModelStructureNode | ComponentModelStructure,
  path: string,
): StructureAssignmentNode {
  const pieces = extractPiecesFromNode(definition).map((piece, index) => ({
    path: `${path}:piece-${index}`,
    definition: piece,
    selectedPieceId: '',
  }))

  const products = extractProductsFromNode(definition).map((product, index) => ({
    path: `${path}:product-${index}`,
    definition: product,
    selectedProductId: '',
  }))

  const subcomponents = extractSubcomponents(definition).map(
    (child, index) => buildAssignmentNode(child, `${path}:sub-${index}`),
  )

  return {
    path,
    definition,
    selectedComponentId: '',
    pieces,
    products,
    subcomponents,
  }
}

export function initializeStructureAssignments(
  structure: ComponentModelStructure | null,
): StructureAssignmentNode | null {
  if (!structure || typeof structure !== 'object') {
    return null
  }
  return buildAssignmentNode(structure, 'root')
}

// ---------------------------------------------------------------------------
// Validation
// ---------------------------------------------------------------------------

export function hasAssignments(node: StructureAssignmentNode | null): boolean {
  if (!node) {
    return false
  }
  if (node.pieces.length > 0 || node.products.length > 0 || node.subcomponents.length > 0) {
    return true
  }
  return node.subcomponents.some((child) => hasAssignments(child))
}

export function isAssignmentNodeComplete(
  node: StructureAssignmentNode,
  isRootNode = false,
): boolean {
  const piecesComplete = node.pieces.every(
    (piece) => !!piece.selectedPieceId && piece.selectedPieceId.length > 0,
  )
  const productsComplete = node.products.every(
    (product) => !!product.selectedProductId && product.selectedProductId.length > 0,
  )
  const subcomponentsComplete = node.subcomponents.every(
    (child) =>
      !!child.selectedComponentId
      && child.selectedComponentId.length > 0
      && isAssignmentNodeComplete(child, false),
  )
  return (
    piecesComplete
    && productsComplete
    && subcomponentsComplete
    && (isRootNode || !!node.selectedComponentId)
  )
}

// ---------------------------------------------------------------------------
// Serialization
// ---------------------------------------------------------------------------

export function stripNullish(input: Record<string, any>) {
  return Object.fromEntries(
    Object.entries(input).filter(
      ([, value]) => value !== null && value !== undefined && value !== '',
    ),
  )
}

export function sanitizeStructureDefinition(
  definition: ComponentModelStructureNode,
) {
  return stripNullish({
    alias: definition.alias ?? null,
    typeComposantId: definition.typeComposantId ?? null,
    typeComposantLabel: definition.typeComposantLabel ?? null,
    modelId: definition.modelId ?? null,
    familyCode: (definition as any).familyCode ?? null,
  })
}

export function sanitizePieceDefinition(definition: ComponentModelPiece) {
  return stripNullish({
    role: (definition as any).role ?? null,
    typePieceId: definition.typePieceId ?? null,
    typePieceLabel: definition.typePieceLabel ?? null,
    reference: definition.reference ?? null,
    familyCode: (definition as any).familyCode ?? null,
    quantity: typeof (definition as any).quantity === 'number' ? (definition as any).quantity : null,
  })
}

export function sanitizeProductDefinition(definition: ComponentModelProduct) {
  return stripNullish({
    role: (definition as any).role ?? null,
    typeProductId: definition.typeProductId ?? null,
    typeProductLabel: (definition as any).typeProductLabel ?? null,
    reference: (definition as any).reference ?? null,
    familyCode: (definition as any).familyCode ?? null,
  })
}

export function serializeStructureAssignments(
  root: StructureAssignmentNode | null,
) {
  if (!root) {
    return null
  }

  const serializeNode = (
    assignment: StructureAssignmentNode,
    isRootNode = false,
  ): Record<string, any> => {
    const serializedPieces = assignment.pieces
      .filter((piece) => !!piece.selectedPieceId)
      .map((piece) =>
        stripNullish({
          path: piece.path,
          definition: sanitizePieceDefinition(piece.definition),
          selectedPieceId: piece.selectedPieceId,
        }),
      )

    const serializedProducts = assignment.products
      .filter((product) => !!product.selectedProductId)
      .map((product) =>
        stripNullish({
          path: product.path,
          definition: sanitizeProductDefinition(product.definition),
          selectedProductId: product.selectedProductId,
        }),
      )

    const serializedSubcomponents = assignment.subcomponents
      .map((child) => serializeNode(child, false))
      .filter((child) => Object.keys(child).length > 0)

    const base: Record<string, any> = {
      path: assignment.path,
      definition: sanitizeStructureDefinition(assignment.definition),
    }

    if (!isRootNode) {
      base.selectedComponentId = assignment.selectedComponentId
    }
    if (serializedPieces.length) {
      base.pieces = serializedPieces
    }
    if (serializedProducts.length) {
      base.products = serializedProducts
    }
    if (serializedSubcomponents.length) {
      base.subcomponents = serializedSubcomponents
    }

    return stripNullish(base)
  }

  const serializedRoot = serializeNode(root, true)
  if (
    (!serializedRoot.pieces || serializedRoot.pieces.length === 0)
    && (!serializedRoot.products || serializedRoot.products.length === 0)
    && (!serializedRoot.subcomponents || serializedRoot.subcomponents.length === 0)
  ) {
    return null
  }
  return serializedRoot
}
