import { BadRequestException } from '@nestjs/common';
import { NovedadesService } from './novedades.service';

describe('NovedadesService', () => {
  const createService = () => {
    const prisma = {
      $transaction: jest.fn(async (cb: any) => cb(prisma)),
      rrhh_asistencia_novedades: {
        findFirst: jest.fn(),
        update: jest.fn(),
        delete: jest.fn(),
        updateMany: jest.fn(),
      },
      rrhh_liquidaciones_cabecera: {
        updateMany: jest.fn().mockResolvedValue({ count: 1 }),
      },
    };
    const service = new NovedadesService(prisma as any);
    return { service, prisma };
  };

  it('actualizar novedad reservada marca la preliquidación como pendiente de recálculo', async () => {
    const { service, prisma } = createService();
    prisma.rrhh_asistencia_novedades.findFirst.mockResolvedValue({
      id: 'nov-1',
      empresa_id: 'empresa-1',
      liquidacion_id: null,
      preliquidacion_id: 'liq-pre-1',
    });
    prisma.rrhh_asistencia_novedades.update.mockResolvedValue({ id: 'nov-1' });

    await service.actualizar('nov-1', 'empresa-1', { observacion: 'ajuste' });

    expect(prisma.rrhh_liquidaciones_cabecera.updateMany).toHaveBeenCalledWith({
      where: { id: 'liq-pre-1', estado: 'PRE_LIQUIDACION' },
      data: { recalculo_pendiente: true, updated_at: expect.any(Date) },
    });
  });

  it('eliminar novedad reservada marca la preliquidación como pendiente de recálculo', async () => {
    const { service, prisma } = createService();
    prisma.rrhh_asistencia_novedades.findFirst.mockResolvedValue({
      id: 'nov-2',
      empresa_id: 'empresa-1',
      liquidacion_id: null,
      preliquidacion_id: 'liq-pre-2',
    });
    prisma.rrhh_asistencia_novedades.delete.mockResolvedValue({ id: 'nov-2' });

    await service.eliminar('nov-2', 'empresa-1');

    expect(prisma.rrhh_liquidaciones_cabecera.updateMany).toHaveBeenCalledWith({
      where: { id: 'liq-pre-2', estado: 'PRE_LIQUIDACION' },
      data: { recalculo_pendiente: true, updated_at: expect.any(Date) },
    });
  });

  it('bloquea modificación cuando la novedad ya fue consumida en liquidación cerrada', async () => {
    const { service, prisma } = createService();
    prisma.rrhh_asistencia_novedades.findFirst.mockResolvedValue({
      id: 'nov-3',
      empresa_id: 'empresa-1',
      liquidacion_id: 'liq-cerrada',
      preliquidacion_id: null,
    });

    await expect(
      service.actualizar('nov-3', 'empresa-1', { observacion: 'no debe poder' }),
    ).rejects.toThrow(BadRequestException);
    expect(prisma.rrhh_liquidaciones_cabecera.updateMany).not.toHaveBeenCalled();
  });

  it('anularPresentismo bloquea si la novedad está aplicada a liquidación cerrada', async () => {
    const { service, prisma } = createService();
    prisma.rrhh_asistencia_novedades.findFirst.mockResolvedValue({
      id: 'nov-4',
      empresa_id: 'empresa-1',
      liquidacion_id: 'liq-1',
      estado: 'CONFIRMADA',
    });

    await expect(
      service.anularPresentismo('nov-4', 'empresa-1', 'user-1', 'motivo test'),
    ).rejects.toThrow('Anule la liquidación primero');
  });

  it('anularPresentismo marca estado ANULADA cuando corresponde', async () => {
    const { service, prisma } = createService();
    prisma.rrhh_asistencia_novedades.findFirst.mockResolvedValue({
      id: 'nov-5',
      empresa_id: 'empresa-1',
      liquidacion_id: null,
      observacion: null,
      estado: 'CONFIRMADA',
    });
    prisma.rrhh_asistencia_novedades.update.mockResolvedValue({
      id: 'nov-5',
      estado: 'ANULADA',
    });

    const res = await service.anularPresentismo('nov-5', 'empresa-1', 'user-1', 'ajuste');
    expect(res.anulado).toBe(true);
    expect(prisma.rrhh_asistencia_novedades.update).toHaveBeenCalledWith({
      where: { id: 'nov-5' },
      data: expect.objectContaining({ estado: 'ANULADA' }),
    });
  });
});
