import type { Calidad, CategoriaMaterial, CatalogItem } from '@/budget/types';
import type { AbstractedPreferences, PreferenceAjuste, PreferenceExtra, RawCallData } from './preferences';
import {
  AJUSTE_LEXICON,
  CALIDAD_LEXICON,
  ELEMENTOS_LEXICON,
  ESTILO_LEXICON,
  ESTRUCTURAL_LEXICON,
  MATERIAL_LEXICON,
  normalizeText,
} from './lexicon';

export interface PreferenceExtractor {
  extract(raw: RawCallData, catalog: CatalogItem[]): AbstractedPreferences;
}

function hit(text: string, keywords: string[]): boolean {
  return keywords.some((k) => text.includes(k));
}

function pickItem(
  catalog: CatalogItem[],
  categoria: CategoriaMaterial,
  calidad: Calidad,
  matched: string[],
): CatalogItem | null {
  const ofCat = catalog.filter((c) => c.categoria === categoria);
  const byDescriptor = ofCat.filter((c) => {
    const hay = normalizeText(`${c.nombre} ${c.descriptorRender}`);
    return matched.some((k) => hay.includes(k));
  });
  return (
    byDescriptor.find((c) => c.calidad === calidad) ??
    byDescriptor[0] ??
    ofCat.find((c) => c.calidad === calidad && c.esDefault) ??
    null
  );
}

export class DeterministicExtractor implements PreferenceExtractor {
  extract(raw: RawCallData, catalog: CatalogItem[]): AbstractedPreferences {
    const text = normalizeText(raw.tasteText ?? '');

    let calidadGlobal: Calidad = raw.calidad ?? 'media';
    if (!raw.calidad) {
      for (const e of CALIDAD_LEXICON) {
        if (hit(text, e.keywords)) {
          calidadGlobal = e.calidad;
          break;
        }
      }
    }

    const materialSelections: Partial<Record<CategoriaMaterial, string>> = {};
    for (const e of MATERIAL_LEXICON) {
      const matched = e.keywords.filter((k) => text.includes(k));
      if (matched.length === 0) continue;
      const item = pickItem(catalog, e.categoria, calidadGlobal, matched);
      if (item) materialSelections[e.categoria] = item.id;
    }

    const estructural = raw.estructural ?? hit(text, ESTRUCTURAL_LEXICON);

    const elementos: PreferenceExtra[] = (ELEMENTOS_LEXICON[raw.tipoReforma] ?? [])
      .filter((el) => hit(text, el.keywords))
      .map((el) => ({ key: el.key, label: el.label, importe: el.importe }));

    const estiloRender = ESTILO_LEXICON.filter((s) => text.includes(s));

    const ajustes: PreferenceAjuste[] = AJUSTE_LEXICON.filter((a) => hit(text, a.keywords)).map(
      (a) => ({ label: a.label, tipo: a.tipo, valor: a.valor, motivo: a.motivo }),
    );

    const hasM2 = raw.m2Suelo != null && raw.m2Suelo > 0;
    const signals =
      (estiloRender.length > 0 ? 1 : 0) +
      (elementos.length > 0 ? 1 : 0) +
      (Object.keys(materialSelections).length > 0 ? 1 : 0);
    let confianza: AbstractedPreferences['confianza'] = 'baja';
    if (hasM2 && signals >= 2) confianza = 'alta';
    else if (hasM2 || signals >= 1) confianza = 'media';

    const camposFaltantes: string[] = [];
    if (!hasM2) camposFaltantes.push('m2');
    if (raw.urgencia == null) camposFaltantes.push('urgencia');
    if (raw.presupuestoTarget == null) camposFaltantes.push('presupuestoTarget');
    if (text.length === 0) camposFaltantes.push('preferencias');

    const partes: string[] = [`Acabado ${calidadGlobal}`];
    if (estiloRender.length) partes.push(`estilo ${estiloRender.join(', ')}`);
    if (elementos.length) partes.push(`pide ${elementos.map((e) => e.label.toLowerCase()).join(', ')}`);
    if (estructural) partes.push('con cambios estructurales');
    const resumen = partes.join('; ') + '.';

    return {
      calidadGlobal,
      materialSelections,
      estructural,
      urgencia: raw.urgencia,
      presupuestoTarget: raw.presupuestoTarget,
      elementos,
      estiloRender,
      ajustes,
      confianza,
      resumen,
      camposFaltantes,
    };
  }
}

export const deterministicExtractor = new DeterministicExtractor();
