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

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

import * as visitesMedicalesService from '@/services/visites-medicales.service';
import { prisma } from '@/lib/prisma';
type CreateVisitePayload = Parameters<typeof visitesMedicalesService.createVisiteMedicale>[0];

describe('Unit - services/visites-medicales', () => {
    beforeEach(() => {
        vi.resetAllMocks();
    });

    it('listVisitesMedicales: should return { items, count } with pagination', async () => {
        const limit = 25;
        const offset = 50;
        const items = [
            { id: 1, id_salarie: 955, commentaire: 'RAS' },
            { id: 2, id_salarie: 956, commentaire: 'A revoir' },
        ];
        const count = 42;

        vi.mocked(prisma.visites_medicales.findMany).mockResolvedValue(items as never);
        vi.mocked(prisma.visites_medicales.count).mockResolvedValue(count as never);

        const res = await visitesMedicalesService.listVisitesMedicales(limit, offset);

        expect(prisma.visites_medicales.findMany).toHaveBeenCalledWith({
            orderBy: { id: 'desc' },
            take: limit,
            skip: offset,
            select: {
                id: true,
                id_salarie: true,
                datedde: true,
                dec: true,
                dvp: true,
                obv: true,
                mtc: true,
                apt: true,
                vmp: true,
                commentaire: true,
                dateprochainevm: true,
                daterappel: true,
                date_creation: true,
            },
        });
        expect(prisma.visites_medicales.count).toHaveBeenCalledWith();
        expect(res).toEqual({ items, count });
    });

    it('listVisitesMedicales: should return empty items with count 0', async () => {
        vi.mocked(prisma.visites_medicales.findMany).mockResolvedValue([] as never);
        vi.mocked(prisma.visites_medicales.count).mockResolvedValue(0 as never);

        const res = await visitesMedicalesService.listVisitesMedicales(10, 0);

        expect(res).toEqual({ items: [], count: 0 });
    });

    it('getVisiteMedicaleById: should return visite when exists', async () => {
        const id = 1;
        const visite = { id, id_salarie: 955, commentaire: 'ok' };

        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue(visite as never);

        const res = await visitesMedicalesService.getVisiteMedicaleById(id);

        expect(prisma.visites_medicales.findUnique).toHaveBeenCalledWith({
            where: { id },
            select: {
                id: true,
                id_salarie: true,
                datedde: true,
                dec: true,
                dvp: true,
                obv: true,
                mtc: true,
                apt: true,
                vmp: true,
                commentaire: true,
                dateprochainevm: true,
                daterappel: true,
                date_creation: true,
            },
        });
        expect(res).toEqual(visite);
    });

    it('getVisiteMedicaleById: should return null when missing', async () => {
        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue(null as never);

        const res = await visitesMedicalesService.getVisiteMedicaleById(404);

        expect(res).toBeNull();
    });

    it('createVisiteMedicale: should call prisma.create and return created visite', async () => {
        const payload: CreateVisitePayload = { id_salarie: 955, commentaire: 'creee' };
        const created = { id: 1, ...payload };

        vi.mocked(prisma.visites_medicales.create).mockResolvedValue(created as never);

        const res = await visitesMedicalesService.createVisiteMedicale(payload);

        expect(prisma.visites_medicales.create).toHaveBeenCalledWith({
            data: payload,
            select: {
                id: true,
                id_salarie: true,
                datedde: true,
                dec: true,
                dvp: true,
                obv: true,
                mtc: true,
                apt: true,
                vmp: true,
                commentaire: true,
                dateprochainevm: true,
                daterappel: true,
                date_creation: true,
            },
        });
        expect(res).toEqual(created);
    });
    it('updateVisiteMedicaleById: should update visit medical when ID exists', async () => {
        const id = 1;
        const payload: Partial<CreateVisitePayload> = { commentaire: "Updated" };
        const updatedVisit = { id: id, ...payload };

        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue({ id: id } as never);
        vi.mocked(prisma.visites_medicales.update).mockResolvedValue(updatedVisit as never);


        const res = await visitesMedicalesService.updateVisiteMedicaleById(id, payload);

        expect(prisma.visites_medicales.findUnique).toHaveBeenCalledWith({
            where: { id: id },
        });
        expect(prisma.visites_medicales.update).toHaveBeenCalledWith({
            where: { id: id },
            select: {
                id: true,
                id_salarie: true,
                datedde: true,
                dec: true,
                dvp: true,
                obv: true,
                mtc: true,
                apt: true,
                vmp: true,
                commentaire: true,
                dateprochainevm: true,
                daterappel: true,
                date_creation: true,
            },
            data: payload,
        });
        expect(res).toEqual(updatedVisit);
    });

    it('updateVisiteMedicaleById: should return null when missing', async () => {
        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue(null as never);

        const res = await visitesMedicalesService.updateVisiteMedicaleById(999, { commentaire: 'x' } as Partial<CreateVisitePayload>);

        expect(prisma.visites_medicales.update).not.toHaveBeenCalled();
        expect(res).toBeNull();
    });

    it('deleteVisiteMedicaleById: should return null when missing', async () => {
        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue(null as never);

        const res = await visitesMedicalesService.deleteVisiteMedicaleById(999);

        expect(prisma.visites_medicales.delete).not.toHaveBeenCalled();
        expect(res).toBeNull();
    });

    it('deleteVisiteMedicaleById: should delete and return visite when exists', async () => {
        const id = 1;
        const deletedVisite = { id, id_salarie: 955, commentaire: 'deleted' };

        vi.mocked(prisma.visites_medicales.findUnique).mockResolvedValue({ id } as never);
        vi.mocked(prisma.visites_medicales.delete).mockResolvedValue(deletedVisite as never);

        const res = await visitesMedicalesService.deleteVisiteMedicaleById(id);

        expect(prisma.visites_medicales.findUnique).toHaveBeenCalledWith({
            where: { id },
        });
        expect(prisma.visites_medicales.delete).toHaveBeenCalledWith({
            where: { id },
            select: {
                id: true,
                id_salarie: true,
                datedde: true,
                dec: true,
                dvp: true,
                obv: true,
                mtc: true,
                apt: true,
                vmp: true,
                commentaire: true,
                dateprochainevm: true,
                daterappel: true,
                date_creation: true,
            },
        });
        expect(res).toEqual(deletedVisite);
    });
});
