import {
  createEmptyComponentModelStructure,
  type ComponentModelCustomField,
  type ComponentModelStructure,
  type ComponentModelStructureNode,
} from '../types/inventory'
import { mergeDefinitionsWithValues } from '../utils/customFields'

// Import for internal use in this file
import { sanitizeCustomFields, sanitizePieces, sanitizeProducts, sanitizeSubcomponents } from './componentStructureSanitize'
import { hydrateCustomFields, hydratePieces, hydrateProducts, hydrateSubcomponents, mapComponentCustomFields, mapComponentPieces, mapComponentProducts, mapSubcomponents } from './componentStructureHydrate'

// Re-export sanitize functions so existing imports continue to work
export {
  toStringArray,
  extractFieldValueObject,
  sanitizeCustomFields,
  sanitizePieces,
  sanitizeProducts,
  sanitizeSubcomponents,
} from './componentStructureSanitize'

// Re-export hydrate functions so existing imports continue to work
export {
  hydrateCustomFields,
  hydratePieces,
  hydrateProducts,
  hydrateSubcomponents,
  mapComponentCustomFields,
  mapComponentPieces,
  mapComponentProducts,
  mapSubcomponents,
} from './componentStructureHydrate'

export const isPlainObject = (value: unknown): value is Record<string, unknown> => {
  return value !== null && typeof value === 'object' && !Array.isArray(value)
}

export interface ModelStructurePreview {
  customFields: number
  pieces: number
  products: number
  subcomponents: number
}

export const defaultStructure = (): ComponentModelStructure => ({
  ...createEmptyComponentModelStructure(),
})

const ensureStructureShape = (input: any): ComponentModelStructure => {
  const base = createEmptyComponentModelStructure()
  if (!isPlainObject(input)) {
    return base
  }

  const clone: ComponentModelStructure = {
    ...base,
    customFields: Array.isArray((input as any).customFields) ? (input as any).customFields : [],
    pieces: Array.isArray((input as any).pieces) ? (input as any).pieces : [],
    products: Array.isArray((input as any).products) ? (input as any).products : [],
    subcomponents: Array.isArray((input as any).subcomponents)
      ? (input as any).subcomponents
      : Array.isArray((input as any).subComponents)
        ? (input as any).subComponents
        : [],
    typeComposantId: typeof (input as any).typeComposantId === 'string' ? (input as any).typeComposantId : undefined,
    typeComposantLabel: typeof (input as any).typeComposantLabel === 'string'
      ? (input as any).typeComposantLabel
      : undefined,
    modelId: typeof (input as any).modelId === 'string' ? (input as any).modelId : undefined,
    familyCode: typeof (input as any).familyCode === 'string' ? (input as any).familyCode : undefined,
    alias: typeof (input as any).alias === 'string' ? (input as any).alias : undefined,
  }

  return clone
}

export const cloneStructure = (input: any): ComponentModelStructure => {
  try {
    const cloned = JSON.parse(JSON.stringify(input ?? defaultStructure()))
    return ensureStructureShape(cloned)
  } catch (_error) {
    return defaultStructure()
  }
}

export const normalizeStructureForEditor = (input: any): ComponentModelStructure => {
  const source = cloneStructure(input)

  const merged = mergeDefinitionsWithValues(source.customFields, [])
  const customFields: ComponentModelCustomField[] = merged.map((field) => ({
    name: field.name,
    type: field.type as ComponentModelCustomField['type'],
    required: field.required,
    machineContextOnly: field.machineContextOnly,
    options: field.options,
    defaultValue: field.defaultValue,
    optionsText: field.optionsText,
    id: field.customFieldId ?? undefined,
    customFieldId: field.customFieldId ?? undefined,
    orderIndex: field.orderIndex,
  }))

  const result: ComponentModelStructure = {
    customFields,
    pieces: sanitizePieces(source.pieces),
    products: sanitizeProducts(source.products),
    subcomponents: hydrateSubcomponents(source.subcomponents),
  }

  if (typeof source.typeComposantId === 'string' && source.typeComposantId.length > 0) {
    result.typeComposantId = source.typeComposantId
  }
  if (typeof source.typeComposantLabel === 'string' && source.typeComposantLabel.length > 0) {
    result.typeComposantLabel = source.typeComposantLabel
  }
  if (typeof source.modelId === 'string' && source.modelId.length > 0) {
    result.modelId = source.modelId
  }
  if (typeof source.familyCode === 'string' && source.familyCode.length > 0) {
    result.familyCode = source.familyCode
  }
  if (typeof source.alias === 'string' && source.alias.length > 0) {
    result.alias = source.alias
  }

  return result
}

export const normalizeStructureForSave = (input: any): any => {
  const source = cloneStructure(input)

  const sanitizedCustomFields = sanitizeCustomFields(source.customFields)
  const backendCustomFields = sanitizedCustomFields.map((field) => {
    const value: Record<string, any> = {
      type: field.type,
      required: !!field.required,
      machineContextOnly: !!field.machineContextOnly,
    }
    if (field.options && field.options.length) {
      value.options = field.options
    }
    if (field.defaultValue !== undefined && field.defaultValue !== null && field.defaultValue !== '') {
      value.defaultValue = field.defaultValue
    }
    const payload: Record<string, any> = {
      key: field.name,
      value,
    }
    if (field.id) {
      payload.id = field.id
    }
    if (field.customFieldId) {
      payload.customFieldId = field.customFieldId
    }
    return payload
  }) as any

  const backendPieces = sanitizePieces(source.pieces).map((piece) => {
    const payload: Record<string, any> = {}
    if ((piece as any).familyCode) {
      payload.familyCode = (piece as any).familyCode
    }
    if (piece.typePieceId) {
      payload.typePieceId = piece.typePieceId
    }
    if (piece.typePieceLabel) {
      payload.typePieceLabel = piece.typePieceLabel
    }
    if (piece.reference) {
      payload.reference = piece.reference
    }
    if ((piece as any).quantity !== undefined && (piece as any).quantity >= 1) {
      payload.quantity = (piece as any).quantity
    }
    return payload
  }) as any

  const backendProducts = sanitizeProducts(source.products).map((product) => {
    const payload: Record<string, any> = {}
    if ((product as any).familyCode) {
      payload.familyCode = (product as any).familyCode
    }
    if (product.typeProductId) {
      payload.typeProductId = product.typeProductId
    }
    if (product.role) {
      payload.role = product.role
    }
    return payload
  }) as any

  const mapSubcomponentForSave = (subcomponent: ComponentModelStructureNode): any => {
    const payload: Record<string, any> = {}
    if (subcomponent.typeComposantId) {
      payload.typeComposantId = subcomponent.typeComposantId
    }
    if (subcomponent.modelId) {
      payload.modelId = subcomponent.modelId
    }
    if (subcomponent.familyCode) {
      payload.familyCode = subcomponent.familyCode
    }
    if (subcomponent.alias) {
      payload.alias = subcomponent.alias
    }
    if (Array.isArray(subcomponent.subcomponents) && subcomponent.subcomponents.length) {
      payload.subcomponents = subcomponent.subcomponents.map(mapSubcomponentForSave)
    }
    return payload
  }

  const backendSubcomponents = sanitizeSubcomponents(source.subcomponents).map(mapSubcomponentForSave) as any

  const result: ComponentModelStructure = {
    customFields: backendCustomFields,
    pieces: backendPieces,
    products: backendProducts,
    subcomponents: backendSubcomponents,
  }

  if (typeof source.typeComposantId === 'string' && source.typeComposantId.length > 0) {
    (result as any).typeComposantId = source.typeComposantId
  }
  if (typeof source.typeComposantLabel === 'string' && source.typeComposantLabel.length > 0) {
    (result as any).typeComposantLabel = source.typeComposantLabel
  }
  if (typeof source.modelId === 'string' && source.modelId.length > 0) {
    (result as any).modelId = source.modelId
  }
  if (typeof source.familyCode === 'string' && source.familyCode.length > 0) {
    (result as any).familyCode = source.familyCode
  }
  if (typeof source.alias === 'string' && source.alias.length > 0) {
    (result as any).alias = source.alias
  }

  return result
}

export const hydrateStructureForEditor = (input: any): ComponentModelStructure => {
  const source = cloneStructure(input)
  return {
    customFields: hydrateCustomFields(source.customFields),
    pieces: hydratePieces(source.pieces),
    products: hydrateProducts(source.products),
    subcomponents: hydrateSubcomponents(
      Array.isArray(source.subcomponents) ? source.subcomponents : (source as any).subComponents,
    ),
    typeComposantId: source.typeComposantId ?? '',
    typeComposantLabel: source.typeComposantLabel ?? '',
    modelId: source.modelId ?? '',
    familyCode: source.familyCode ?? '',
    alias: source.alias ?? '',
  }
}

export const extractStructureFromComponent = (component: any) => {
  if (!component) {
    return defaultStructure()
  }

  const raw = {
    customFields: mapComponentCustomFields(component.customFields),
    pieces: mapComponentPieces(component.pieces),
    products: mapComponentProducts(component.products),
    subcomponents: mapSubcomponents(
      Array.isArray(component?.subcomponents)
        ? component.subcomponents
        : component?.subComponents,
    ),
    typeComposantId: component?.typeComposantId ?? component?.typeComposant?.id ?? '',
    typeComposantLabel: component?.typeComposant?.name ?? component?.typeComposantLabel ?? '',
    modelId: component?.modelId ?? '',
    familyCode: component?.familyCode ?? component?.typeComposant?.code ?? '',
    alias: component?.alias ?? component?.name ?? '',
  }

  return normalizeStructureForEditor(raw)
}

export const computeStructureStats = (structure: any): ModelStructurePreview => {
  if (!structure || typeof structure !== 'object') {
    return { customFields: 0, pieces: 0, products: 0, subcomponents: 0 }
  }

  return {
    customFields: Array.isArray(structure.customFields) ? structure.customFields.length : 0,
    pieces: Array.isArray(structure.pieces) ? structure.pieces.length : 0,
    products: Array.isArray(structure.products) ? structure.products.length : 0,
    subcomponents: Array.isArray(structure.subcomponents)
      ? structure.subcomponents.length
      : Array.isArray(structure.subComponents)
        ? structure.subComponents.length
        : 0,
  }
}

export const formatStructurePreview = (structure: any) => {
  const stats = computeStructureStats(structure)
  if (!stats.customFields && !stats.pieces && !stats.products && !stats.subcomponents) {
    return 'Structure vide'
  }

  const segments: string[] = []
  if (stats.customFields) segments.push(`${stats.customFields} champ(s)`)
  if (stats.pieces) segments.push(`${stats.pieces} pièce(s)`)
  if (stats.products) segments.push(`${stats.products} produit(s)`)
  if (stats.subcomponents) segments.push(`${stats.subcomponents} sous-composant(s)`)
  return segments.join(' • ')
}
