import { ViajeCalculosService } from '../viaje-calculos.service';

/**
 * El resumen toma vendido, cobrado y pendiente de ViajeCobranzaService (que
 * tiene su propio spec) y les suma el costo de la rendición y los km.
 */
describe('ViajeCalculosService.resumen', () => {
  const cobranzaVacia = {
    moneda_base: 'PYG',
    cotizacion_estimada: false,
    vendido: {},
    cobrado: {},
    totales: {
      vendido_base: 0, cobrado_base: 0, cobrado_caja_base: 0, cancelado_viaje_base: 0,
      deuda_anterior_cobrada_base: 0, recibido_base: 0, ajustes_base: 0,
      por_cobrar_base: 0, por_cobrar_vencido_base: 0,
    },
    control: { sin_rendir_base: 0, cobro_ruta_sin_registrar_base: 0 },
    recibos_sin_enganchar: [],
    clientes: [],
  };

  const costosVacios = {
    costo_base: 0,
    rendiciones_activas: 0,
    cotizacion_estimada: false,
    margen: { margen_bruto_base: null, margen_pct: null, cobertura: 0 },
  };

  const crear = ({ cobranza = cobranzaVacia, costos = costosVacios, viaje = {} }: any) => {
    const prisma: any = {};
    const viajes: any = {
      findOne: jest.fn().mockResolvedValue({
        id: 'v-1', empresa_id: 'emp-1', km_salida: 25187, km_retorno: 25790, ...viaje,
      }),
    };
    const service = Object.create(ViajeCalculosService.prototype) as any;
    service.prisma = prisma;
    service.viajes = viajes;
    service.cobranzas = { cobranza: jest.fn().mockResolvedValue(cobranza) };
    service.costosViaje = { costos: jest.fn().mockResolvedValue(costos) };
    return { service };
  };

  it('viaje sin documentos ni rendición devuelve todo en cero y avisa', async () => {
    const { service } = crear({});
    const r = await service.resumen('v-1', 'emp-1');
    expect(r.vendido_base).toBe(0);
    expect(r.cobrado_base).toBe(0);
    expect(r.costo_base).toBe(0);
    expect(r.sin_rendicion).toBe(true);
    expect(r.clientes_visitados).toBe(0);
  });

  it('usa la cobranza para cobrado y pendiente, y suma costo, margen y km', async () => {
    const { service } = crear({
      cobranza: {
        ...cobranzaVacia,
        vendido: { PYG: 1_500_000 },
        cobrado: { PYG: 400_000 },
        totales: {
          ...cobranzaVacia.totales,
          vendido_base: 1_500_000,
          cobrado_base: 400_000,
          deuda_anterior_cobrada_base: 250_000,
          cancelado_sin_enganchar_base: 90_000,
          por_cobrar_base: 1_100_000,
          por_cobrar_vencido_base: 300_000,
        },
        control: { sin_rendir_base: 80_000, cobro_ruta_sin_registrar_base: 20_000 },
        recibos_sin_enganchar: [{ id: 'r-9' }],
        clientes: [{ id: 'cli-1' }, { id: 'cli-2' }, { id: 'sin-cliente' }],
      },
      // Dos rendiciones (vendedor y el que entrega) que suman 300.000.
      costos: {
        costo_base: 300_000,
        rendiciones_activas: 2,
        cotizacion_estimada: false,
        margen: { margen_bruto_base: 450_000, margen_pct: 0.3, cobertura: 1 },
      },
    });

    const r = await service.resumen('v-1', 'emp-1');

    expect(r.vendido).toEqual({ PYG: 1_500_000 });
    expect(r.vendido_base).toBe(1_500_000);
    expect(r.cobrado_base).toBe(400_000);
    // El pendiente es el saldo vivo de las facturas, no vendido − cobrado.
    expect(r.pendiente_base).toBe(1_100_000);
    expect(r.pendiente_vencido_base).toBe(300_000);
    expect(r.deuda_anterior_cobrada_base).toBe(250_000);
    expect(r.cobrado_sin_enganchar_base).toBe(90_000);
    expect(r.sin_rendir_base).toBe(80_000);
    expect(r.cobro_ruta_sin_registrar_base).toBe(20_000);
    expect(r.recibos_sin_enganchar).toBe(1);
    expect(r.costo_base).toBe(300_000);
    expect(r.rendiciones).toBe(2);
    expect(r.margen_bruto_base).toBe(450_000);
    expect(r.resultado_base).toBe(150_000);
    expect(r.cobertura_costo).toBe(1);
    expect(r.viaticos_sobre_venta).toBeCloseTo(0.2);
    expect(r.venta_por_cliente).toBe(750_000);
    expect(r.km_recorrido).toBe(603);
    expect(r.costo_por_km).toBeCloseTo(300_000 / 603);
    // "sin-cliente" no es un cliente visitado.
    expect(r.clientes_visitados).toBe(2);
    expect(r.sin_rendicion).toBe(false);
  });

  it('sin costo de mercadería no hay resultado (no se asume costo cero)', async () => {
    const { service } = crear({});
    const r = await service.resumen('v-1', 'emp-1');
    expect(r.margen_bruto_base).toBeNull();
    expect(r.resultado_base).toBeNull();
    expect(r.viaticos_sobre_venta).toBeNull();
  });

  it('propaga la marca de cotización estimada', async () => {
    const { service } = crear({ cobranza: { ...cobranzaVacia, cotizacion_estimada: true } });
    const r = await service.resumen('v-1', 'emp-1');
    expect(r.cotizacion_estimada).toBe(true);
  });
});
