import { BadRequestException } from '@nestjs/common';
import { AdendasInmService } from './adendas.service';

describe('AdendasInmService.calcular', () => {
  const cuota = (nro: number, monto: number, cobrado: number, estado: string) => ({
    id: `c${nro}`,
    nro,
    tipo: nro === 1 ? 'SENA' : 'CUOTA',
    monto,
    monto_cobrado: cobrado,
    estado,
    descripcion: null,
    fecha_vencimiento: null,
    hito_id: null,
  });
  const op = (estado = 'BOLETO_FIRMADO') =>
    ({
      id: 'op1',
      estado,
      cliente_id: 'cli1',
      unidad_id: 'u1',
      precio_final: 1000,
      moneda: { codigo: 'USD' },
      inm_unidades: { codigo: 'A-0101' },
      inm_operacion_cuotas: [
        cuota(1, 100, 100, 'PAGADA'),
        cuota(2, 300, 120, 'PARCIAL'),
        cuota(3, 300, 0, 'PENDIENTE'),
        cuota(4, 300, 0, 'PENDIENTE'),
      ],
    }) as any;
  const crear = () => {
    const prisma: any = {
      inm_planes_pago: {
        findFirst: jest.fn().mockResolvedValue({
          inm_plan_pago_tramos: [
            {
              orden: 1,
              tipo: 'CUOTA',
              base: 'PORCENTAJE',
              valor: 100,
              cantidad: 4,
              periodicidad_meses: 1,
              inicio_meses: 1,
            },
          ],
        }),
      },
      inm_cobro_cuotas: { aggregate: jest.fn().mockResolvedValue({ _sum: { monto_ajuste: 0 } }) },
    };
    const parametros: any = { obtener: jest.fn().mockResolvedValue({ pct_retencion_rescision: 10 }) };
    return new AdendasInmService(prisma, { log: jest.fn() } as any, {} as any, parametros, {} as any, {} as any);
  };

  it('cambio de plan: el saldo se replanifica, las cobradas no se tocan y la parcial se cierra', async () => {
    const r = await crear().calcular(
      op(),
      { tipo: 'CAMBIO_PLAN', motivo: 'x', plan_id: 'p1', fecha_base: '2026-11-01' },
      'e1',
    );
    expect(r.cobrado).toBe(220);
    expect(r.saldo).toBe(780);
    expect(r.cuotas_anuladas).toEqual([3, 4]);
    expect(r.parciales_cerradas).toEqual([2]);
    expect(r.cuotas_nuevas).toHaveLength(4);
    expect(r.cuotas_nuevas.reduce((a, c) => a + c.monto, 0)).toBe(780);
  });

  it('rescisión: liquida lo cobrado con la retención de los parámetros', async () => {
    const r = await crear().calcular(op('CANCELADA_TOTAL'), { tipo: 'RESCISION', motivo: 'x' }, 'e1');
    expect(r.rescision).toEqual(
      expect.objectContaining({ cobrado: 220, pct_retencion: 10, retencion: 22, a_devolver: 198 }),
    );
    expect(r.cuotas_anuladas).toEqual([2, 3, 4]);
  });

  it('una adenda de cambio de plan sobre una reserva no corresponde', async () => {
    await expect(
      crear().calcular(op('RESERVADA'), { tipo: 'CAMBIO_PLAN', motivo: 'x', plan_id: 'p1' }, 'e1'),
    ).rejects.toBeInstanceOf(BadRequestException);
  });
});
