import { BadRequestException } from '@nestjs/common';
import { GastosService } from './gastos.service';

/**
 * Gasto histórico (Fase 3 del plan Latincomp): comprobante de un sistema anterior, ya
 * pagado y contabilizado allá. Sólo va al Libro IVA y a Marangatu.
 */
describe('GastosService - gasto histórico', () => {
  const armar = (config: Record<string, unknown> = {}) => {
    const tx: any = {
      gasto_cab: { create: jest.fn().mockResolvedValue({ id: 'g1' }) },
      gasto_det: { createMany: jest.fn().mockResolvedValue({ count: 1 }) },
    };
    const prisma: any = { $transaction: jest.fn(async (cb: any) => cb(tx)) };
    const contabilidad = { integrarGasto: jest.fn().mockResolvedValue(undefined) };
    const tesoreria = { integrarGasto: jest.fn().mockResolvedValue({}), revertirGasto: jest.fn() };
    const service = new GastosService(prisma, contabilidad as any, tesoreria as any, {} as any, {} as any);
    const s = service as any;
    jest.spyOn(s, 'getOrCreateConfigCompras').mockResolvedValue({
      generar_cxp_automatico: true,
      incluir_contado_en_orden_pago: false,
      modo_flujo_compra: 'compra_directa',
      ...config,
    });
    jest.spyOn(s, 'isProveedorExterior').mockResolvedValue(false);
    jest.spyOn(s, 'assertComprobanteNoDuplicado').mockResolvedValue(undefined);
    jest.spyOn(s, 'validateRefs').mockResolvedValue(undefined);
    jest.spyOn(s, 'normalizeItems').mockResolvedValue([
      { descripcion: 'Servicio', cantidad: 1, precio_unitario: 110000, porcentaje_iva: 10, subtotal: 100000, monto_iva: 10000, total: 110000 },
    ]);
    jest.spyOn(s, 'assertRequisicionGastoValida').mockResolvedValue(undefined);
    jest.spyOn(s, 'resolverMonedaGasto').mockResolvedValue({ codigo: 'PYG', cotizacion: 1 });
    jest.spyOn(s, 'aplicarEjecucionRequisicion').mockResolvedValue(undefined);
    const cxp = jest.spyOn(s, 'createCuentaPorPagarDesdeGasto').mockResolvedValue(undefined);
    jest.spyOn(s, 'findOne').mockResolvedValue({ id: 'g1' });
    return { service, tx, contabilidad, tesoreria, cxp };
  };

  const dto = (cabecera: Record<string, unknown>) =>
    ({
      cabecera: {
        proveedor_id: 'prov-1',
        timbrado: '12345678',
        establecimiento: '001',
        punto_expedicion: '001',
        numero_factura: '0000001',
        ...cabecera,
      },
      items: [{ descripcion: 'Servicio', cantidad: 1, precio_unitario: 110000, porcentaje_iva: 10 }],
    }) as any;

  it('de contado no pide medio de pago, queda pagado y no arma cuenta a pagar, asiento ni tesorería', async () => {
    const { service, tx, contabilidad, tesoreria, cxp } = armar();
    await service.create(dto({ forma_pago: 'CONTADO', es_historico: true }), 'emp-1', 'u-1');

    const data = tx.gasto_cab.create.mock.calls[0][0].data;
    expect(data).toMatchObject({ es_historico: true, estado: 'pagada', medio_pago_id: null, cuenta_tesoreria_id: null });
    expect(cxp).not.toHaveBeenCalled();
    expect(contabilidad.integrarGasto).not.toHaveBeenCalled();
    expect(tesoreria.integrarGasto).not.toHaveBeenCalled();
  });

  it('a crédito también queda pagado (se pagó en el sistema anterior) y sin cuenta a pagar', async () => {
    const { service, tx, cxp } = armar();
    await service.create(dto({ forma_pago: 'CREDITO', es_historico: true }), 'emp-1');
    expect(tx.gasto_cab.create.mock.calls[0][0].data).toMatchObject({ estado: 'pagada', forma_pago: 'CREDITO' });
    expect(cxp).not.toHaveBeenCalled();
  });

  it('ignora el medio de pago aunque venga', async () => {
    const { service, tx } = armar();
    await service.create(dto({ forma_pago: 'CONTADO', es_historico: true, medio_pago_id: 'm1', cuenta_tesoreria_id: 'c1' }), 'emp-1');
    expect(tx.gasto_cab.create.mock.calls[0][0].data).toMatchObject({ medio_pago_id: null, cuenta_tesoreria_id: null });
  });

  it('no exige requisición aunque la empresa la tenga obligatoria', async () => {
    const { service, tx } = armar({ modo_flujo_compra: 'requisicion_obligatoria' });
    await service.create(dto({ forma_pago: 'CONTADO', es_historico: true }), 'emp-1');
    expect(tx.gasto_cab.create).toHaveBeenCalled();
  });

  it('no se imputa a una importación', async () => {
    const { service } = armar();
    await expect(service.create(dto({ es_historico: true, embarque_id: 'e1' }), 'emp-1')).rejects.toThrow(BadRequestException);
  });

  it('un gasto normal de contado sigue pidiendo medio de pago y arma todo', async () => {
    const { service, cxp, contabilidad } = armar();
    await expect(service.create(dto({ forma_pago: 'CONTADO' }), 'emp-1')).rejects.toThrow(/Medio de pago requerido/);
    await service.create(dto({ forma_pago: 'CREDITO' }), 'emp-1');
    expect(cxp).toHaveBeenCalled();
    expect(contabilidad.integrarGasto).toHaveBeenCalled();
  });
});
