import { ClientesService } from './clientes.service';

/**
 * La decisión de "¿puede comprar a crédito?" vive acá y en ningún otro lado:
 * POS retail y facturación clásica leen esta misma respuesta.
 *
 * Reglas, en orden:
 *  1. credito_habilitado = false → no vende a crédito, sin importar el resto.
 *  2. bloqueado_credito = true   → rechaza, tenga tope o no.
 *  3. sin tope (limite null/0)   → permite, saldo_disponible null.
 *  4. con tope                   → controla cupo contra el saldo pendiente.
 */
describe('ClientesService.verificarCredito', () => {
  const crearService = (cliente: Record<string, any> | null) => {
    const prisma: any = {
      clientes: { findUnique: jest.fn().mockResolvedValue(cliente) },
    };
    return new ClientesService(prisma, {} as any, {} as any, {} as any);
  };

  const clienteBase = {
    id: 'cli-1',
    credito_habilitado: true,
    limite_credito: null,
    saldo_pendiente: 0,
    bloqueado_credito: false,
  };

  it('rechaza cuando el cliente no tiene habilitada la venta a crédito', async () => {
    const service = crearService({ ...clienteBase, credito_habilitado: false, limite_credito: 5_000_000 });

    const r = await service.verificarCredito('cli-1', 100_000);

    expect(r.permitido).toBe(false);
    expect(r.mensaje).toMatch(/no tiene habilitada la venta a crédito/i);
  });

  it('rechaza al cliente bloqueado aunque no tenga tope cargado', async () => {
    // Antes el "sin tope" salía por un return anticipado y el bloqueo nunca se
    // evaluaba: un cliente bloqueado a mano seguía facturando a crédito.
    const service = crearService({ ...clienteBase, bloqueado_credito: true, saldo_pendiente: 800_000 });

    const r = await service.verificarCredito('cli-1', 100_000);

    expect(r.permitido).toBe(false);
    expect(r.mensaje).toMatch(/bloqueado/i);
  });

  it('permite sin tope cuando el límite está vacío', async () => {
    const service = crearService({ ...clienteBase, saldo_pendiente: 9_999_999 });

    const r = await service.verificarCredito('cli-1', 4_000_000);

    expect(r).toEqual({ permitido: true, sin_tope: true, saldo_disponible: null });
  });

  it('trata el límite 0 igual que el vacío: sin tope', async () => {
    const service = crearService({ ...clienteBase, limite_credito: 0 });

    const r = await service.verificarCredito('cli-1', 4_000_000);

    expect(r.permitido).toBe(true);
    expect(r.sin_tope).toBe(true);
  });

  it('permite cuando el monto entra en el cupo disponible', async () => {
    const service = crearService({ ...clienteBase, limite_credito: 5_000_000, saldo_pendiente: 1_000_000 });

    const r = await service.verificarCredito('cli-1', 4_000_000);

    expect(r).toEqual({ permitido: true, sin_tope: false, saldo_disponible: 4_000_000 });
  });

  it('rechaza cuando el monto excede el cupo disponible', async () => {
    const service = crearService({ ...clienteBase, limite_credito: 5_000_000, saldo_pendiente: 1_000_000 });

    const r = await service.verificarCredito('cli-1', 4_000_001);

    expect(r.permitido).toBe(false);
    expect(r.saldo_disponible).toBe(4_000_000);
    expect(r.mensaje).toMatch(/excede el crédito disponible/i);
  });

  it('falla si el cliente no existe', async () => {
    const service = crearService(null);

    await expect(service.verificarCredito('cli-x', 1)).rejects.toThrow('Cliente no encontrado');
  });
});
