/**
 * Parte pura de la importación de leads (ticket CRM-11). Sin Nest ni Prisma, para
 * poder probar el mapeo y la validación contra planillas reales sin base.
 */

/** Campos de un lead que la planilla puede traer. `nombre` es el único imprescindible. */
export const CAMPOS_IMPORTABLES = [
  'nombre',
  'empresa_nombre',
  'ruc',
  'dv',
  'telefono',
  'email',
  'origen',
  'campana',
] as const;

export type CampoImportable = (typeof CAMPOS_IMPORTABLES)[number];

/**
 * Encabezados que vimos en planillas de clientes (AGOGO, DOBA) y los que exporta
 * el propio ERP. Se comparan normalizados: sin acentos, sin signos, en minúsculas.
 */
const ALIAS: Record<CampoImportable, string[]> = {
  nombre: ['nombre', 'nombre y apellido', 'nombre completo', 'contacto', 'cliente', 'razon social', 'nombres'],
  empresa_nombre: ['empresa', 'empresa nombre', 'razon social empresa', 'comercio', 'negocio'],
  ruc: ['ruc', 'ruc ci', 'ruc o ci', 'documento', 'ci', 'cedula', 'nro documento'],
  dv: ['dv', 'digito verificador', 'digito'],
  telefono: ['telefono', 'tel', 'celular', 'whatsapp', 'cel', 'movil', 'telefono celular', 'nro telefono'],
  email: ['email', 'correo', 'correo electronico', 'mail', 'e mail'],
  origen: ['origen', 'canal', 'fuente', 'procedencia'],
  campana: ['campana', 'campania', 'campaign', 'utm campaign'],
};

/** Minúsculas, sin acentos y con un solo espacio: así "Teléfono / Celular" y "telefono celular" coinciden. */
export function normalizarEncabezado(texto: string): string {
  return texto
    .normalize('NFD')
    .replace(/[̀-ͯ]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, ' ')
    .trim();
}

/**
 * Propone qué columna de la planilla corresponde a cada campo. Lo que no se
 * reconoce queda sin mapear y lo resuelve la persona en la pantalla: adivinar de
 * más es peor que preguntar.
 */
export function sugerirMapeo(encabezados: string[]): Partial<Record<CampoImportable, string>> {
  const porNormalizado = new Map<string, string>();
  for (const h of encabezados) {
    const n = normalizarEncabezado(h);
    if (n && !porNormalizado.has(n)) porNormalizado.set(n, h);
  }

  const mapeo: Partial<Record<CampoImportable, string>> = {};
  const usados = new Set<string>();

  for (const campo of CAMPOS_IMPORTABLES) {
    for (const alias of ALIAS[campo]) {
      const original = porNormalizado.get(alias);
      if (original && !usados.has(original)) {
        mapeo[campo] = original;
        usados.add(original);
        break;
      }
    }
  }
  return mapeo;
}

export interface FilaCruda {
  [columna: string]: unknown;
}

export interface FilaLead {
  /** Número de fila en la planilla contando el encabezado, que es lo que ve la persona en Excel. */
  fila: number;
  nombre: string;
  empresa_nombre?: string;
  ruc?: string;
  dv?: string;
  telefono?: string;
  email?: string;
  origen?: string;
  campana?: string;
}

/** Celda a texto: Excel entrega números y fechas, no siempre strings. */
export function aTexto(valor: unknown): string {
  if (valor === null || valor === undefined) return '';
  if (valor instanceof Date) return valor.toISOString().slice(0, 10);
  if (typeof valor === 'object') return '';  // "[object Object]" no es el nombre de nadie
  if (typeof valor === 'number' || typeof valor === 'boolean') return String(valor);
  return typeof valor === 'string' ? valor.trim() : '';
}

/**
 * Separa RUC y DV cuando vienen pegados ("80144315-6"), que es como los escribe
 * casi todo el mundo. Si no hay guion, devuelve el DV que se haya mapeado aparte.
 */
export function partirRuc(crudo: string, dvAparte: string): { ruc: string; dv: string } {
  const limpio = crudo.replace(/[^0-9kK-]/g, '');
  const guion = limpio.indexOf('-');
  if (guion > 0) {
    return { ruc: limpio.slice(0, guion), dv: limpio.slice(guion + 1, guion + 2) };
  }
  return { ruc: limpio, dv: dvAparte.replace(/[^0-9kK]/g, '').slice(0, 1) };
}

export function construirFila(
  cruda: FilaCruda,
  mapeo: Partial<Record<CampoImportable, string>>,
  fila: number,
): FilaLead {
  const leer = (campo: CampoImportable) => {
    const columna = mapeo[campo];
    return columna ? aTexto(cruda[columna]) : '';
  };

  const { ruc, dv } = partirRuc(leer('ruc'), leer('dv'));

  return {
    fila,
    nombre: leer('nombre'),
    empresa_nombre: leer('empresa_nombre') || undefined,
    ruc: ruc || undefined,
    dv: dv || undefined,
    telefono: leer('telefono') || undefined,
    email: leer('email') || undefined,
    origen: leer('origen') || undefined,
    campana: leer('campana') || undefined,
  };
}

/** Una fila sin ninguna celda con contenido: Excel arrastra cientos al final. */
export function filaVacia(cruda: FilaCruda): boolean {
  return Object.values(cruda).every((v) => aTexto(v) === '');
}
