import { ContextoDiagnostico, diagnosticarDocumento, DocumentoParaDiagnostico } from './diagnosticar-documento';

const AHORA = new Date('2026-10-23T12:00:00Z');
const hace = (horas: number) => new Date(AHORA.getTime() - horas * 3_600_000);
const ctx: ContextoDiagnostico = { ahora: AHORA, horasParaTrabado: 2, sifenActivo: true };

function doc(parcial: Partial<DocumentoParaDiagnostico>): DocumentoParaDiagnostico {
  return {
    tipo: 'FACTURA',
    estado: 'Enviado',
    nro_lote: '1',
    estado_sifen: null,
    mensaje_sifen: null,
    tipo_aprobacion: null,
    fecha_envio_sifen: null,
    created_at: hace(1),
    updated_at: hace(1),
    evento_aplicado: null,
    estado_evento: null,
    mensaje_evento: null,
    fecha_evento: null,
    estado_envio_email: null,
    ...parcial,
  };
}

describe('diagnosticarDocumento', () => {
  it('aprobado → resuelto, y nunca sugerir reemitir', () => {
    const v = diagnosticarDocumento(doc({ estado_sifen: 'Aprobado' }), ctx);
    expect(v).toMatchObject({ situacion: 'APROBADO', resultado: 'RESUELTO', noReemitir: true });
  });

  it('aprobado localmente en empresa sin facturación electrónica', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Cancelado', mensaje_sifen: 'Aprobado localmente — empresa sin facturación electrónica' }),
      ctx,
    );
    expect(v.situacion).toBe('CANCELADO');
    const sinSifen = diagnosticarDocumento(doc({ estado_sifen: null }), { ...ctx, sifenActivo: false });
    expect(sinSifen.situacion).toBe('APROBADO_SIN_SIFEN');
  });

  describe('"Documento firmado" / Enviado / Pendiente', () => {
    it('menos de 2 h: en proceso, esperar, no reemitir', () => {
      const v = diagnosticarDocumento(doc({ estado_sifen: 'Documento firmado', fecha_envio_sifen: hace(0.5) }), ctx);
      expect(v).toMatchObject({
        situacion: 'EN_PROCESO',
        resultado: 'RESUELTO',
        accionCliente: 'esperar',
        noReemitir: true,
      });
    });

    it('2 h o más: trabado, no resuelto, no reemitir', () => {
      const v = diagnosticarDocumento(doc({ estado_sifen: 'Documento firmado', fecha_envio_sifen: hace(30) }), ctx);
      expect(v).toMatchObject({
        situacion: 'TRABADO',
        resultado: 'NO_RESUELTO',
        motivo: 'trabado_sifen',
        noReemitir: true,
      });
      expect(v.horasEsperando).toBeCloseTo(30);
    });

    it('Pendiente "Enviado a sifen" reciente', () => {
      const v = diagnosticarDocumento(
        doc({ estado_sifen: 'Pendiente', mensaje_sifen: 'Enviado a sifen', fecha_envio_sifen: hace(0.1) }),
        ctx,
      );
      expect(v.situacion).toBe('EN_PROCESO');
    });
  });

  it('"Rechazado" por duplicado reciente: puede estar aprobado, no reemitir', () => {
    const v = diagnosticarDocumento(
      doc({
        estado_sifen: 'Rechazado',
        mensaje_sifen: 'Documento electrónico duplicado',
        fecha_envio_sifen: hace(0.5),
      }),
      ctx,
    );
    expect(v).toMatchObject({ situacion: 'POSIBLE_DUPLICADO_APROBADO', resultado: 'RESUELTO', noReemitir: true });
  });

  it('"Rechazado" por duplicado viejo: trabado', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Rechazado', mensaje_sifen: 'Documento electrónico duplicado', fecha_envio_sifen: hace(48) }),
      ctx,
    );
    expect(v).toMatchObject({ situacion: 'TRABADO', motivo: 'trabado_sifen' });
  });

  it('rechazo por dato del cliente: autoservicio, con el mensaje sin "TEST - "', () => {
    const v = diagnosticarDocumento(
      doc({
        estado_sifen: 'Rechazado',
        mensaje_sifen: 'TEST - RUC del receptor inexistente en la base de datos de Marangatu',
      }),
      ctx,
    );
    expect(v).toMatchObject({
      situacion: 'RECHAZO_DATO_CLIENTE',
      resultado: 'RESUELTO_AUTOSERVICIO',
      accionCliente: 'corregir_y_reenviar',
      mensaje: 'RUC del receptor inexistente en la base de datos de Marangatu',
      ambienteTest: true,
    });
  });

  it('rechazo por falla de SIFEN: no es dato del cliente, reenviar tal cual', () => {
    const v = diagnosticarDocumento(doc({ estado_sifen: 'Rechazado', mensaje_sifen: 'Error Inesperado' }), ctx);
    expect(v).toMatchObject({
      situacion: 'FALLA_SIFEN_TRANSITORIA',
      resultado: 'RESUELTO_AUTOSERVICIO',
      accionCliente: 'reenviar',
    });
  });

  it('firma adelantada: falla de plataforma, no resuelto', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Rechazado', mensaje_sifen: 'La fecha y hora de la firma digital es adelantada' }),
      ctx,
    );
    expect(v).toMatchObject({
      situacion: 'FALLA_PLATAFORMA',
      resultado: 'NO_RESUELTO',
      motivo: 'posible_error_sistema',
    });
  });

  it('empresa sin datos en e-FacturaHub: lo resuelve Novasis', () => {
    const v = diagnosticarDocumento(
      doc({
        estado_sifen: 'Error',
        mensaje_sifen:
          'Middleware SIFEN error 400: {"status":"error","message":"No se encontraron datos de la empresa para validar el lote"}',
      }),
      ctx,
    );
    expect(v).toMatchObject({ situacion: 'EMPRESA_NO_EN_HUB', resultado: 'NO_RESUELTO', motivo: 'sync_empresa_hub' });
    expect(v.mensaje).toBe('No se encontraron datos de la empresa para validar el lote');
  });

  it('Error de red reciente: la cola reintenta; si persiste, falla persistente', () => {
    const reciente = diagnosticarDocumento(
      doc({ estado_sifen: 'Error', mensaje_sifen: 'Timeout al conectar', fecha_envio_sifen: hace(0.2) }),
      ctx,
    );
    expect(reciente).toMatchObject({
      situacion: 'FALLA_SIFEN_TRANSITORIA',
      resultado: 'RESUELTO',
      accionCliente: 'esperar',
    });
    const viejo = diagnosticarDocumento(
      doc({ estado_sifen: 'Error', mensaje_sifen: 'Timeout al conectar', fecha_envio_sifen: hace(5) }),
      ctx,
    );
    expect(viejo).toMatchObject({ resultado: 'NO_RESUELTO', motivo: 'falla_sifen_persistente' });
  });

  it('error del middleware sin motivo legible: no resuelto', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Error', mensaje_sifen: 'Middleware SIFEN error 400: {}' }),
      ctx,
    );
    expect(v).toMatchObject({ resultado: 'NO_RESUELTO', motivo: 'posible_error_sistema' });
  });

  it('certificado vencido: lo renueva el cliente', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Rechazado', mensaje_sifen: 'El certificado digital se encuentra vencido' }),
      ctx,
    );
    expect(v).toMatchObject({ situacion: 'RECHAZO_CERTIFICADO', accionCliente: 'renovar_certificado' });
  });

  describe('evento de cancelación', () => {
    it('aprobado, o "ya se encuentra con el mismo evento"', () => {
      const a = diagnosticarDocumento(
        doc({ estado_sifen: 'Aprobado', evento_aplicado: 'ECAN', estado_evento: 'Aprobado' }),
        ctx,
      );
      expect(a.evento?.situacion).toBe('APROBADO');
      const b = diagnosticarDocumento(
        doc({
          estado_sifen: 'Aprobado',
          evento_aplicado: 'ECAN',
          estado_evento: 'Rechazado',
          mensaje_evento: 'CDC ya se encuentra con el mismo evento solicitado',
        }),
        ctx,
      );
      expect(b.evento?.situacion).toBe('APROBADO');
    });

    it('rechazado: revisar la alerta (reenviar / liberar)', () => {
      const v = diagnosticarDocumento(
        doc({
          estado_sifen: 'Aprobado',
          evento_aplicado: 'ECAN',
          estado_evento: 'Rechazado',
          mensaje_evento: 'Error Inesperado',
        }),
        ctx,
      );
      expect(v.evento).toMatchObject({ situacion: 'RECHAZADO', accionCliente: 'revisar_alerta_evento' });
    });

    it('pendiente viejo: trabado', () => {
      const v = diagnosticarDocumento(
        doc({ estado_sifen: 'Aprobado', evento_aplicado: 'EINU', estado_evento: 'Pendiente', fecha_evento: hace(10) }),
        ctx,
      );
      expect(v.evento?.situacion).toBe('TRABADO');
    });
  });

  describe('casos que salieron del barrido sobre la copia de producción', () => {
    it('Pendiente en el ERP, nunca enviado: lo envía el cliente (no es trabado)', () => {
      const v = diagnosticarDocumento(
        doc({ estado: 'Pendiente', nro_lote: null, estado_sifen: null, created_at: hace(400) }),
        ctx,
      );
      expect(v).toMatchObject({
        situacion: 'SIN_ENVIAR',
        resultado: 'RESUELTO_AUTOSERVICIO',
        accionCliente: 'enviar_a_sifen',
        noReemitir: true,
      });
    });

    it('sin estado SIFEN pero con lote: sí puede estar trabado', () => {
      const v = diagnosticarDocumento(
        doc({ estado: 'Pendiente', nro_lote: '77', estado_sifen: null, created_at: hace(10) }),
        ctx,
      );
      expect(v.situacion).toBe('TRABADO');
    });

    it('Inutilizado: resuelto, con el motivo del rechazo original', () => {
      const v = diagnosticarDocumento(
        doc({
          estado: 'Anulado',
          estado_sifen: 'Inutilizado',
          mensaje_sifen: 'RUC del receptor inexistente en la base de datos de Marangatu',
        }),
        ctx,
      );
      expect(v).toMatchObject({ situacion: 'INUTILIZADO', resultado: 'RESUELTO', claseMensaje: 'informativo' });
      expect(v.mensaje).toBe('RUC del receptor inexistente en la base de datos de Marangatu');
    });

    it('"valores inválidos" sin detalle: el cliente no tiene qué corregir', () => {
      const v = diagnosticarDocumento(
        doc({
          estado_sifen: 'Rechazado',
          mensaje_sifen:
            'Middleware SIFEN error 400: {"status":"error","message":"Se detectaron valores inválidos en algunos documentos","aceptados":0,"rechazados":1,"response":{"Acepta',
        }),
        ctx,
      );
      expect(v).toMatchObject({
        claseMensaje: 'validacion_sin_detalle',
        resultado: 'NO_RESUELTO',
        motivo: 'posible_error_sistema',
      });
    });

    it('XML con elementos en otro orden: falla de plataforma; valor inválido: dato del cliente', () => {
      const orden = diagnosticarDocumento(
        doc({
          estado_sifen: 'Rechazado',
          mensaje_sifen: 'XML malformado: [El elemento esperado es: iDenTarj en lugar de: iForProPa]',
        }),
        ctx,
      );
      expect(orden.situacion).toBe('FALLA_PLATAFORMA');
      const valor = diagnosticarDocumento(
        doc({
          estado_sifen: 'Rechazado',
          mensaje_sifen: 'XML malformado: [El valor HB-F7206 del elemento: dGtin es invalido]',
        }),
        ctx,
      );
      expect(valor.situacion).toBe('RECHAZO_DATO_CLIENTE');
    });

    it('en documentos aprobados el mensaje es informativo, no "dato del cliente"', () => {
      const v = diagnosticarDocumento(doc({ estado_sifen: 'Aprobado', mensaje_sifen: 'CDC encontrado' }), ctx);
      expect(v.claseMensaje).toBe('informativo');
    });
  });

  it('correo sin destinatario: cargar el email del receptor', () => {
    const v = diagnosticarDocumento(
      doc({ estado_sifen: 'Aprobado', estado_envio_email: 'Error: No recipients defined' }),
      ctx,
    );
    expect(v.correo).toEqual({ estado: 'sin_destinatario', accionCliente: 'cargar_email_receptor' });
  });
});
