/**
 * Por qué un registro quedó sin asiento. La conciliación detecta QUÉ falta;
 * esto explica POR QUÉ no se generó solo, que es lo primero que pregunta la
 * empresa cuando ve cientos de pendientes ("¿el sistema falló?").
 *
 * Es una causa probable reconstruida con evidencia (fechas de activación y de
 * mapeos, intentos registrados). Cuando no hay evidencia, se dice.
 */

import { textoReglaRota } from '../contabilidad/services/avisos-mapeo.service';

export type CausaPendiente =
  | 'ANTERIOR_A_CONTABILIDAD'
  | 'IMPORTADO'
  | 'SIN_SALDO_PUENTE'
  | 'FALTA_MAPEO'
  | 'MAPEO_POSTERIOR'
  | 'IMPORTACION_EXTRACTO'
  | 'INTENTO_FALLIDO'
  | 'INTEGRACION_SILENCIOSA'
  | 'SIN_REGISTRO';

export interface ExplicacionPendiente {
  codigo: CausaPendiente;
  texto: string;
  /** Conceptos a mapear (causa FALTA_MAPEO): el botón lleva a Mapeo con ellos. */
  conceptos?: string[];
}

export interface EvidenciaPendiente {
  /** Cuándo se creó el registro operativo (no su fecha contable). */
  creadoEn: Date | null;
  /** Cuándo se activó el módulo Contabilidad para la empresa. */
  activacionContabilidad: Date | null;
  origenTipo: string | null;
  /** Documento traído por importación (Marangatu, sistema anterior): no pasó por el flujo que asienta. */
  importadoDesde?: string | null;
  /** Categorías/conceptos que el registro necesita y se mapearon después de crearlo. */
  mapeosPosteriores: Array<{ nombre: string; fecha: Date }>;
  /** Último intento registrado de generarle asiento que falló. */
  ultimoIntento: { fecha: Date; error: string } | null;
  /**
   * La integración en tiempo real quedó auditada como exitosa pero no dejó
   * asiento (bug de sincronización con la transacción, corregido el 21/09/2026).
   */
  integracionMarcadaOk?: Date | null;
  /**
   * Conceptos que el último intento de asentarlo pidió y que hoy siguen sin un
   * mapeo usable, con la recomendación ya resuelta a cuenta concreta.
   */
  faltaMapeo?: {
    conceptos: string[];
    recomendaciones: Record<string, string>;
    reglas?: Record<string, number[]>;
    /** Qué corregir cuando no es un concepto del mapeo (medio de pago y su cuenta). */
    detalles?: Record<string, string>;
  } | null;
  /** Cierre de importación cuya cuenta puente no tiene saldo de la importación: no hay nada que trasladar. */
  sinSaldoPuente?: boolean;
}

const fmt = (d: Date) =>
  `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}/${d.getFullYear()}`;

export function explicarPendiente(e: EvidenciaPendiente): ExplicacionPendiente {
  if (e.creadoEn && e.activacionContabilidad && e.creadoEn < e.activacionContabilidad) {
    return {
      codigo: 'ANTERIOR_A_CONTABILIDAD',
      texto: `Se creó el ${fmt(e.creadoEn)}, antes de activar Contabilidad (${fmt(e.activacionContabilidad)}). En ese momento no se generaban asientos.`,
    };
  }

  if (e.importadoDesde) {
    return {
      codigo: 'IMPORTADO',
      texto: `Importado desde ${e.importadoDesde}. Los documentos importados no pasan por la emisión, que es donde se genera el asiento: se contabilizan desde acá.`,
    };
  }

  // Antes que la falta de mapeo: aunque se mapee, sin saldo en la puente el
  // cierre no genera asiento.
  if (e.sinSaldoPuente) {
    return {
      codigo: 'SIN_SALDO_PUENTE',
      texto:
        'La cuenta puente no recibió costos de esta importación por documentos del sistema: no hay nada que trasladar. Si el costo se registró con un asiento manual, el cierre también va manual.',
    };
  }

  if (e.faltaMapeo && e.faltaMapeo.conceptos.length > 0) {
    const reglas = e.faltaMapeo.reglas ?? {};
    const detalles = e.faltaMapeo.detalles ?? {};
    const porRegla = e.faltaMapeo.conceptos.filter((c) => reglas[c]?.length);
    const conDetalle = e.faltaMapeo.conceptos.filter((c) => !reglas[c]?.length && detalles[c]);
    const sinMapear = e.faltaMapeo.conceptos.filter((c) => !reglas[c]?.length && !detalles[c]);
    const detalle = sinMapear
      .map((c) => (e.faltaMapeo!.recomendaciones[c] ? `${c} (recomendado: ${e.faltaMapeo!.recomendaciones[c]})` : c))
      .join(', ');
    // Una excepción con cuenta que no sirve no es "falta mapear": el defecto puede estar bien.
    const partes = [
      ...porRegla.map((c) => textoReglaRota(c, reglas[c])),
      ...conDetalle.map((c) => detalles[c]),
      ...(sinMapear.length ? [`falta mapear ${detalle}`] : []),
    ];
    const arreglo = porRegla.length
      ? `Una excepción activa no se edita: retirala y duplicala con otra cuenta${sinMapear.length ? '; lo que falta, mapealo' : ''}, y regenerá desde acá.`
      : sinMapear.length
        ? 'El sistema no elige cuentas por su cuenta: mapealo y regenerá desde acá.'
        : 'El sistema no elige cuentas por su cuenta: corregilo y regenerá desde acá.';
    return {
      codigo: 'FALTA_MAPEO',
      texto: `No se contabilizó porque ${partes.join(' y ')}. ${arreglo}`,
      conceptos: e.faltaMapeo.conceptos,
    };
  }

  if (e.mapeosPosteriores.length > 0) {
    const ultimo = e.mapeosPosteriores.reduce((a, b) => (b.fecha > a.fecha ? b : a));
    const nombres = e.mapeosPosteriores.map((m) => `"${m.nombre}"`).join(', ');
    return {
      codigo: 'MAPEO_POSTERIOR',
      texto: `Cuando se creó, ${nombres} no tenía cuenta contable asignada, así que el asiento se omitió. El mapeo se cargó el ${fmt(ultimo.fecha)}.`,
    };
  }

  if (e.origenTipo === 'IMPORT_EXTRACTO') {
    return {
      codigo: 'IMPORTACION_EXTRACTO',
      texto: 'Importado desde el extracto bancario. La importación masiva no genera asientos automáticamente: se contabiliza desde acá.',
    };
  }

  if (e.integracionMarcadaOk) {
    return {
      codigo: 'INTEGRACION_SILENCIOSA',
      texto: `El ${fmt(e.integracionMarcadaOk)} el sistema registró la contabilización como exitosa, pero el asiento no llegó a generarse: la integración corría antes de que el recibo quedara confirmado en la base (error corregido el 21/09/2026). Se contabiliza desde acá.`,
    };
  }

  if (e.ultimoIntento) {
    return {
      codigo: 'INTENTO_FALLIDO',
      texto: `El último intento de generarle asiento (${fmt(e.ultimoIntento.fecha)}) falló: ${e.ultimoIntento.error}`,
    };
  }

  return {
    codigo: 'SIN_REGISTRO',
    texto: 'No quedó registrado por qué no se generó en su momento. Lo que sí está verificado es que hoy no tiene asiento.',
  };
}
