import { envs } from 'src/config';
import { MiddlewareSifenService } from './middleware-sifen.service';

/**
 * Eventos SIFEN de notas de remisión: al aprobarse un ECAN/EINU la remisión se
 * anula y se revierten sus efectos (stock y cantidades aplicadas a facturas),
 * igual que la anulación manual.
 */
describe('MiddlewareSifenService - eventos de nota de remisión', () => {
  const CDC = '07800959256001003000000622026091414013417188';
  const remision = {
    id: 'rem-1',
    empresa_id: 'emp-1',
    cdc: CDC,
    dest: '001',
    dpunexp: '003',
    dnumdoc: '0000006',
    estado: 'Aprobado',
    estado_sifen: 'Aprobado',
    evento_aplicado: 'ECAN',
    estado_evento: 'Pendiente',
    mensaje_evento: 'motivo',
    fecha_evento: new Date(),
  };

  const urlOriginal = envs.middlewareSifenUrl;
  const fetchOriginal = global.fetch;
  beforeAll(() => {
    (envs as any).middlewareSifenUrl = 'http://middleware.test';
  });
  afterAll(() => {
    (envs as any).middlewareSifenUrl = urlOriginal;
    global.fetch = fetchOriginal;
  });

  const crearService = (doc: Record<string, unknown>, estadoRetorno: string | null) => {
    const prisma: any = {
      nota_remision_cab: {
        findMany: jest.fn(({ where }) => Promise.resolve(where.estado_evento ? [doc] : [])),
        findFirst: jest.fn().mockResolvedValue(doc),
        update: jest.fn().mockResolvedValue({}),
        updateMany: jest.fn().mockResolvedValue({ count: 1 }),
      },
      empresas_sucursales: { findMany: jest.fn().mockResolvedValue([]) },
    };
    const audit = { log: jest.fn().mockResolvedValue(undefined) };
    const alertas = { resolver: jest.fn().mockResolvedValue(true), registrar: jest.fn().mockResolvedValue(undefined) };
    const reversionRemision = { revertirRemision: jest.fn().mockResolvedValue({ revertida: true, stockRepuesto: 2 }) };
    const service = new MiddlewareSifenService(
      {} as any,
      prisma,
      audit as any,
      {} as any,
      {} as any,
      {} as any,
      {} as any,
      alertas as any,
      reversionRemision as any,
    );
    jest.spyOn(service, 'login').mockResolvedValue({ token: 't' } as any);
    global.fetch = jest.fn().mockResolvedValue({
      status: 200,
      json: async () => ({
        status: 'success',
        response: {
          [CDC]: {
            estado_evento: 'Documento Firmado',
            retorno_sifen: estadoRetorno
              ? { estado: estadoRetorno, mensaje: `Evento ${estadoRetorno}`, protocolo: null, codrespuesta: '0600', fecha_retorno: '15-09-2026 08:44:50' }
              : null,
          },
        },
      }),
    }) as any;
    return { service, prisma, reversionRemision };
  };

  it('ECAN aprobado: marca Cancelado y revierte la remisión', async () => {
    const { service, prisma, reversionRemision } = crearService(remision, 'Aprobado');

    const res = await service.sincronizarSifen('emp-1', 'nota_remision', 'evento');

    expect(res.actualizados).toBe(1);
    const data = prisma.nota_remision_cab.update.mock.calls[0][0].data;
    expect(data).toMatchObject({ estado_evento: 'Aprobado', estado_sifen: 'Cancelado' });
    // `estado: 'Anulado'` lo pone la reversión: si lo marcara el update, la reversión lo vería ya anulado y no repondría stock.
    expect(data).not.toHaveProperty('estado');
    expect(reversionRemision.revertirRemision).toHaveBeenCalledWith('rem-1', 'emp-1');
  });

  it('EINU aprobado: marca Inutilizado y revierte la remisión', async () => {
    const { service, prisma, reversionRemision } = crearService(
      { ...remision, estado: 'Rechazado', estado_sifen: 'Rechazado', evento_aplicado: 'EINU' },
      'Aprobado',
    );

    await service.sincronizarSifen('emp-1', 'nota_remision', 'evento');

    expect(prisma.nota_remision_cab.update.mock.calls[0][0].data).toMatchObject({ estado_sifen: 'Inutilizado' });
    expect(reversionRemision.revertirRemision).toHaveBeenCalledWith('rem-1', 'emp-1');
  });

  it('evento rechazado: guarda el rechazo y la remisión sigue vigente', async () => {
    const { service, prisma, reversionRemision } = crearService(remision, 'Rechazado');

    await service.sincronizarSifen('emp-1', 'nota_remision', 'evento');

    expect(prisma.nota_remision_cab.update.mock.calls[0][0].data).toMatchObject({ estado_evento: 'Rechazado' });
    expect(reversionRemision.revertirRemision).not.toHaveBeenCalled();
  });

  it('sin respuesta de SIFEN todavía: no toca la remisión', async () => {
    const { service, prisma, reversionRemision } = crearService(remision, null);

    await service.sincronizarSifen('emp-1', 'nota_remision', 'evento');

    expect(prisma.nota_remision_cab.update).not.toHaveBeenCalled();
    expect(reversionRemision.revertirRemision).not.toHaveBeenCalled();
  });

  it('empresa sin SIFEN: la cancelación se aplica localmente y revierte la remisión', async () => {
    const { service, prisma, reversionRemision } = crearService(
      { ...remision, evento_aplicado: null, estado_evento: null },
      null,
    );
    jest.spyOn(service, 'empresaUsaSifen').mockResolvedValue(false);

    const res = await service.enviarEvento('emp-1', 'nota_remision', 'cancelacion', 'rem-1', 'motivo');

    expect(res.success).toBe(true);
    expect(prisma.nota_remision_cab.update.mock.calls[0][0].data).toMatchObject({
      estado_sifen: 'Cancelado',
      evento_aplicado: 'ECAN',
      estado_evento: 'Aprobado',
    });
    expect(reversionRemision.revertirRemision).toHaveBeenCalledWith('rem-1', 'emp-1');
  });
});
