import { BadRequestException } from '@nestjs/common';
import { TesChequeEstado, TesChequeTipo } from '../dto/tes-cheque.dto';
import { TesChequeService } from './tes-cheques.service';

describe('TesChequeService — fecha_movimiento al depositar/debitar', () => {
  const crearService = (chequeOverrides: Record<string, any> = {}) => {
    const cheque = {
      id: 'chq-1',
      empresa_id: 'emp-1',
      tipo: TesChequeTipo.RECIBIDO,
      estado: TesChequeEstado.EN_CARTERA,
      numero_cheque: '123',
      titular: 'Juan Perez',
      monto: 100000,
      fecha_emision: new Date('2026-08-01'),
      fecha_vencimiento: null,
      ...chequeOverrides,
    };

    const cuenta = { id: 'cta-1', nombre: 'Cuenta 1', moneda: 'PYG', activo: true };

    const prisma: any = {
      tes_cheques: {
        findFirst: jest.fn().mockResolvedValue(cheque),
        update: jest.fn(),
      },
      tes_cuentas: {
        findFirst: jest.fn().mockResolvedValue(cuenta),
        update: jest.fn().mockResolvedValue(undefined),
      },
      tes_categorias: {
        findFirst: jest.fn().mockResolvedValue({ id: 'cat-1' }),
        create: jest.fn(),
      },
      tes_movimientos: {
        create: jest.fn().mockResolvedValue({ id: 'mov-1' }),
      },
    };
    prisma.tes_cheques.update.mockImplementation(({ data }: any) =>
      Promise.resolve({ ...cheque, ...data, cuenta }),
    );
    prisma.$transaction = jest.fn((cb: any) => cb(prisma));

    const contabilidad = { integrarMovimientoTesoreria: jest.fn().mockResolvedValue(undefined) };
    const audit = { log: jest.fn().mockResolvedValue(undefined) };

    const service = new TesChequeService(prisma, contabilidad as any, audit as any);
    return { service, prisma };
  };

  describe('depositar', () => {
    it('usa la fecha_movimiento provista para el movimiento contable', async () => {
      const { service, prisma } = crearService();

      await service.depositar(
        'chq-1',
        { cuenta_id: 'cta-1', fecha_movimiento: '2026-08-20' } as any,
        'emp-1',
        'user-1',
      );

      const dataMovimiento = prisma.tes_movimientos.create.mock.calls[0][0].data;
      expect(dataMovimiento.fecha.toISOString().slice(0, 10)).toBe('2026-08-20');
    });

    it('sin fecha_movimiento usa la fecha de hoy', async () => {
      const { service, prisma } = crearService();
      const hoy = new Date().toISOString().slice(0, 10);

      await service.depositar('chq-1', { cuenta_id: 'cta-1' } as any, 'emp-1', 'user-1');

      const dataMovimiento = prisma.tes_movimientos.create.mock.calls[0][0].data;
      expect(dataMovimiento.fecha.toISOString().slice(0, 10)).toBe(hoy);
    });

    it('rechaza fecha_movimiento futura', async () => {
      const { service } = crearService();
      const manana = new Date();
      manana.setDate(manana.getDate() + 1);
      const fechaFutura = manana.toISOString().slice(0, 10);

      await expect(
        service.depositar(
          'chq-1',
          { cuenta_id: 'cta-1', fecha_movimiento: fechaFutura } as any,
          'emp-1',
          'user-1',
        ),
      ).rejects.toBeInstanceOf(BadRequestException);
    });

    it('rechaza fecha_movimiento anterior a la emisión del cheque', async () => {
      const { service } = crearService({ fecha_emision: new Date('2026-08-01') });

      await expect(
        service.depositar(
          'chq-1',
          { cuenta_id: 'cta-1', fecha_movimiento: '2026-07-01' } as any,
          'emp-1',
          'user-1',
        ),
      ).rejects.toBeInstanceOf(BadRequestException);
    });

    it('acreditado_en refleja el momento de la acción, no la fecha_movimiento pasada', async () => {
      const { service, prisma } = crearService();
      const antes = Date.now();

      await service.depositar(
        'chq-1',
        { cuenta_id: 'cta-1', fecha_movimiento: '2026-08-01' } as any,
        'emp-1',
        'user-1',
      );

      const dataCheque = prisma.tes_cheques.update.mock.calls[0][0].data;
      expect(dataCheque.acreditado_en.getTime()).toBeGreaterThanOrEqual(antes);
    });
  });

  describe('debitar', () => {
    const crearServiceEmitido = (overrides: Record<string, any> = {}) =>
      crearService({ tipo: TesChequeTipo.EMITIDO, ...overrides });

    it('usa la fecha_movimiento provista para el movimiento contable', async () => {
      const { service, prisma } = crearServiceEmitido();

      await service.debitar(
        'chq-1',
        { cuenta_id: 'cta-1', fecha_movimiento: '2026-08-15' } as any,
        'emp-1',
        'user-1',
      );

      const dataMovimiento = prisma.tes_movimientos.create.mock.calls[0][0].data;
      expect(dataMovimiento.fecha.toISOString().slice(0, 10)).toBe('2026-08-15');
    });

    it('rechaza fecha_movimiento futura', async () => {
      const { service } = crearServiceEmitido();
      const manana = new Date();
      manana.setDate(manana.getDate() + 1);
      const fechaFutura = manana.toISOString().slice(0, 10);

      await expect(
        service.debitar(
          'chq-1',
          { cuenta_id: 'cta-1', fecha_movimiento: fechaFutura } as any,
          'emp-1',
          'user-1',
        ),
      ).rejects.toBeInstanceOf(BadRequestException);
    });
  });
});
