import { describe, it, expect, vi, beforeEach } from 'vitest';

vi.mock('@/lib/prisma', () => ({
    prisma: {
        absences: {
            create: vi.fn(),
            findMany: vi.fn(),
            findUnique: vi.fn(),
            update: vi.fn(),
            delete: vi.fn(),
        },
    },
}));

import * as absenceService from '@/services/absences.service';
import { prisma } from '@/lib/prisma';
type CreateAbsencePayload = Parameters<typeof absenceService.createAbsence>[0];

describe('Unit - services/absences', () => {
    beforeEach(() => {
        vi.resetAllMocks();
    });
    it('listAbsences: should return the absences list with pagination', async () => {
        const limit = 25;
        const offset = 50;
        const expectedAbsences = [
            { id: 1, num_salarie: 5524, typeabsence: "pas la", revenu: true },
            { id: 2, num_salarie: 5, typeabsence: "toujours pas la", revenu: false },
        ];

        vi.mocked(prisma.absences.findMany).mockResolvedValue(expectedAbsences as never);

        const res = await absenceService.listAbsences(limit, offset);

        expect(prisma.absences.findMany).toHaveBeenCalledWith({
            orderBy: [{ id: "asc" }],
            take: limit,
            skip: offset,
        });
        expect(res).toEqual(expectedAbsences);
    });
     it('listAbsences: should return an empty array when no absences exists', async () => {
        const limit = 10;
        const offset = 0;
    
        vi.mocked(prisma.absences.findMany).mockResolvedValue([] as never);
    
        const res = await absenceService.listAbsences(limit, offset);
    
        expect(prisma.absences.findMany).toHaveBeenCalledWith({
          orderBy: [{ id: 'asc' }],
          take: limit,
          skip: offset,
        });
        expect(res).toEqual([]);
      });
      it('getAbsenceById: Should return the absence for the given ID ', async () => {
        const id = 1;
        const expectedAbsence = { id: 1, num_salarie: 5524, typeabsence: "pas la", revenu: true };
    
        vi.mocked(prisma.absences.findUnique).mockResolvedValue(expectedAbsence as never);
    
        const res = await absenceService.getAbsenceById(id);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(res).toEqual(expectedAbsence);
      });
      it('getAbsenceById: should return null when absence does not exist', async () => {
        const id = 404;
    
        vi.mocked(prisma.absences.findUnique).mockResolvedValue(null as never);
    
        const res = await absenceService.getAbsenceById(id);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(res).toBeNull();
      });
      it('createAbsence: should call prisma.create and return created absence', async () => {
        const payload: CreateAbsencePayload = { id_salarie: 5524, typeabsence: "pas la", revenu: true };
        const created = { id: 1, ...payload };

        vi.mocked(prisma.absences.create).mockResolvedValue(created as never);
    
        const res = await absenceService.createAbsence(payload);
    
        expect(prisma.absences.create).toHaveBeenCalledWith({ data: { typeabsence: payload.typeabsence, revenu: payload.revenu, num_salarie: payload.id_salarie } });
        expect(res).toEqual(created);
      });
    
      it('updateAbsenceById: should update absence when ID exists', async () => {
        const id = 1;
        const payload = { typeabsence: 'absent' } as Partial<CreateAbsencePayload>;
        const updatedAbsence = { id: id, ...payload };

        vi.mocked(prisma.absences.findUnique).mockResolvedValue({ id: id } as never);
        vi.mocked(prisma.absences.update).mockResolvedValue(updatedAbsence as never);
    
        const res = await absenceService.updateAbsenceById(id, payload);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(prisma.absences.update).toHaveBeenCalledWith({
          where: { id: id },
          data: payload,
        });
        expect(res).toEqual(updatedAbsence);
      });
      it('updateAbsenceById: should return null when ID does not exist', async () => {
        const id = 99999;

        const payload = { typeabsence: 'Nope' } as Partial<CreateAbsencePayload>;

        vi.mocked(prisma.absences.findUnique).mockResolvedValue(null as never);
    
        const res = await absenceService.updateAbsenceById(id, payload);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(prisma.absences.update).not.toHaveBeenCalled();
        expect(res).toBeNull();
      });
      it('deleteAbsenceById: should delete and return absence ', async () => {
        const id = 1;
        const deletedAbsence = { id: id, typeabsence: 'Delete' };
    
        vi.mocked(prisma.absences.findUnique).mockResolvedValue({ id: id } as never);
        vi.mocked(prisma.absences.delete).mockResolvedValue(deletedAbsence as never);
    
        const res = await absenceService.deleteAbsenceById(id);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(prisma.absences.delete).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(res).toEqual(deletedAbsence);
      });
      it('deleteAbsenceById: should return null when ID does not exist', async () => {
        const id = 55555;
    
        vi.mocked(prisma.absences.findUnique).mockResolvedValue(null as never);
    
        const res = await absenceService.deleteAbsenceById(id);
    
        expect(prisma.absences.findUnique).toHaveBeenCalledWith({
          where: { id: id },
        });
        expect(prisma.absences.delete).not.toHaveBeenCalled();
        expect(res).toBeNull();
      });
})