import {
  createEmptyPieceModelStructure,
  createEmptyProductModelStructure,
  type PieceModelCustomField,
  type PieceModelProduct,
  type PieceModelStructure,
  type PieceModelStructureEditorField,
  type PieceModelStructureForEditor,
  type ProductModelStructure,
} from '../types/inventory'
import { isPlainObject, sanitizeProducts, hydrateProducts } from './componentStructure'

export const defaultPieceStructure = (): PieceModelStructure => ({
  ...createEmptyPieceModelStructure(),
})

export const defaultProductStructure = (): ProductModelStructure => ({
  ...createEmptyProductModelStructure(),
})

const ensurePieceStructureShape = (input: any): PieceModelStructure => {
  const base = createEmptyPieceModelStructure()
  if (!isPlainObject(input)) {
    return base
  }

  const clone: PieceModelStructure = {
    ...base,
    customFields: Array.isArray((input as any).customFields) ? (input as any).customFields : [],
    products: Array.isArray((input as any).products) ? (input as any).products : [],
  }

  for (const [key, value] of Object.entries(input as Record<string, unknown>)) {
    if (key === 'customFields' || key === 'products') {
      continue
    }
    clone[key] = value
  }

  return clone
}

export const clonePieceStructure = (input: any): PieceModelStructure => {
  try {
    const cloned = JSON.parse(JSON.stringify(input ?? defaultPieceStructure()))
    return ensurePieceStructureShape(cloned)
  } catch (_error) {
    return defaultPieceStructure()
  }
}

export const cloneProductStructure = (input: any): ProductModelStructure => {
  return clonePieceStructure(input)
}

const sanitizePieceCustomFields = (fields: any[]): PieceModelCustomField[] => {
  if (!Array.isArray(fields)) {
    return []
  }

  return fields
    .map((field, index) => {
      const name = typeof field?.name === 'string' ? field.name.trim() : ''
      if (!name) {
        return null
      }

      const type = typeof field?.type === 'string' && field.type ? field.type : 'text'
      const required = !!field?.required

      let options: string[] | undefined
      if (type === 'select') {
        const rawOptions = typeof field?.optionsText === 'string'
          ? field.optionsText
          : Array.isArray(field?.options)
            ? field.options.join('\n')
            : ''
        const parsed = rawOptions
          .split(/\r?\n/)
          .map((option: string) => option.trim())
          .filter((option: string) => option.length > 0)
        options = parsed.length > 0 ? parsed : undefined
      }

      const result: PieceModelCustomField = { name, type, required, machineContextOnly: !!field?.machineContextOnly }
      if (options) {
        result.options = options
      }
      const defaultValue =
        field?.defaultValue !== undefined && field?.defaultValue !== null && field?.defaultValue !== ''
          ? String(field.defaultValue)
          : null
      if (defaultValue !== null) {
        result.defaultValue = defaultValue
      }
      if (typeof field?.id === 'string' && field.id) {
        result.id = field.id
      }
      if (typeof field?.customFieldId === 'string' && field.customFieldId) {
        result.customFieldId = field.customFieldId
      }
      const orderIndex = typeof field?.orderIndex === 'number' ? field.orderIndex : index
      result.orderIndex = orderIndex
      return result
    })
    .filter((field): field is PieceModelCustomField => !!field)
}

const sanitizePieceProducts = (products: any[]): PieceModelProduct[] => {
  return sanitizeProducts(products) as PieceModelProduct[]
}

export const normalizePieceStructureForSave = (input: any): PieceModelStructure => {
  const source = clonePieceStructure(input)
  const restEntries = Object.entries(source).filter(
    ([key]) => key !== 'customFields' && key !== 'products',
  )
  return {
    ...Object.fromEntries(restEntries),
    products: sanitizePieceProducts(source.products || []),
    customFields: sanitizePieceCustomFields(source.customFields),
  }
}

const hydratePieceCustomFields = (fields: any[]): PieceModelStructureEditorField[] => {
  if (!Array.isArray(fields)) {
    return []
  }

  return fields.map((field, index) => ({
    name: field?.name ?? '',
    type: field?.type ?? 'text',
    required: !!field?.required,
    machineContextOnly: !!field?.machineContextOnly,
    options: Array.isArray(field?.options) ? field.options : undefined,
    optionsText: typeof field?.optionsText === 'string'
      ? field.optionsText
      : Array.isArray(field?.options)
        ? field.options.join('\n')
        : '',
    orderIndex: typeof field?.orderIndex === 'number' ? field.orderIndex : index,
    ...(field?.id ? { id: field.id } : {}),
    ...(field?.customFieldId ? { customFieldId: field.customFieldId } : {}),
  }))
}

export const hydratePieceStructureForEditor = (input: any): PieceModelStructureForEditor => {
  const source = clonePieceStructure(input)
  const payload: PieceModelStructureForEditor = {
    ...Object.fromEntries(
      Object.entries(source).filter(([key]) => key !== 'customFields' && key !== 'products'),
    ),
    products: hydrateProducts(source.products || []) as PieceModelProduct[],
    customFields: hydratePieceCustomFields(source.customFields),
  }
  return payload
}

export const formatPieceStructurePreview = (structure: any) => {
  if (!structure || typeof structure !== 'object') {
    return 'Aucun champ personnalisé'
  }

  const customFields = Array.isArray((structure as any).customFields)
    ? (structure as any).customFields.length
    : 0
  const products = Array.isArray((structure as any).products)
    ? (structure as any).products.length
    : 0

  if (!customFields && !products) {
    return 'Aucun produit ni champ personnalisé'
  }

  const segments: string[] = []
  if (products) {
    segments.push(`${products} produit(s)`)
  }
  if (customFields) {
    segments.push(`${customFields} champ(s) personnalisé(s)`)
  }

  return segments.join(' · ')
}

export const normalizeProductStructureForSave = (input: any): ProductModelStructure =>
  normalizePieceStructureForSave(input)

export const hydrateProductStructureForEditor = (input: any) =>
  hydratePieceStructureForEditor(input)

export const formatProductStructurePreview = (structure: any) =>
  formatPieceStructurePreview(structure)
