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

const { requireAuthMock, getVisiteMedicaleDetailsMock, updateVisiteMedicaleFeedMock, deleteVisiteMedicaleFeedMock } = vi.hoisted(() => ({
  requireAuthMock: vi.fn(),
  getVisiteMedicaleDetailsMock: vi.fn(),
  updateVisiteMedicaleFeedMock: vi.fn(),
  deleteVisiteMedicaleFeedMock: vi.fn(),
}));

vi.mock('../../../../src/lib/requireAuth', () => ({
  requireAuth: requireAuthMock,
}));

vi.mock('../../../../src/server/visites-medicales.server', () => ({
  getVisiteMedicaleDetails: getVisiteMedicaleDetailsMock,
  updateVisiteMedicaleFeed: updateVisiteMedicaleFeedMock,
  deleteVisiteMedicaleFeed: deleteVisiteMedicaleFeedMock,
}));

import { GET, PUT, DELETE } from '../../../../src/app/api/visites-medicales/[id]/route';

const makeCtx = <T extends (...args: any[]) => any>(fn: T, params: Record<string, string>) => ({ params: Promise.resolve(params) } as unknown as Parameters<T>[1]);

describe('Unit — /api/visites-medicales/[id] route', () => {
  beforeEach(() => {
    vi.resetAllMocks();
    requireAuthMock.mockReturnValue(null);
  });

  it('GET returns 200 when visites-medicale exists', async () => {
    getVisiteMedicaleDetailsMock.mockResolvedValue({ visiteMedicale: { TCS: 'Alice', id_VisiteMedicale: 123, id_salarie: 955 } });

    const res = await GET(new Request('http://localhost/api/visites-medicales/123'), makeCtx(GET, { id: '123' }));

    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body).toEqual({ message: 'Visite médicale retrieved successfully', visiteMedicale: { TCS: 'Alice', id_VisiteMedicale: 123, id_salarie: 955 } });
  });

  it('GET returns 400 when id param is invalid', async () => {
    const res = await GET(new Request('http://localhost/api/visites-medicales/abc'), makeCtx(GET, { id: 'abc' }));

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Invalid id parameter');
  });
  it('GET returns auth error when request is unauthorized', async () => {
    // simulate requireAuth returning an HTTP 401 Response
    requireAuthMock.mockReturnValue(new Response('Unauthorized', { status: 401 }));

    const res = await GET(new Request('http://localhost/api/visites-medicales/1'), makeCtx(GET, { id: '1' }));

    expect(res.status).toBe(401);
    expect(getVisiteMedicaleDetailsMock).not.toHaveBeenCalled();
    });
  it('GET returns 404 when not found', async () => {
    getVisiteMedicaleDetailsMock.mockResolvedValue({ visiteMedicale: null });

    const res = await GET(new Request('http://localhost/api/visites-medicales/999'), makeCtx(GET, { id: '999' }));

    expect(res.status).toBe(404);
    const body = await res.json();
    expect(body.message).toBe('Visite médicale not found');
  });

  it('PUT updates and returns 200', async () => {
    updateVisiteMedicaleFeedMock.mockResolvedValue({ visiteMedicale: { TCS: 'Bob', id_VisiteMedicale: 123, id_salarie: 955 } });

    const res = await PUT(
      new Request('http://localhost/api/visites-medicales/123', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ TCS: 'Bob' }) }),
      makeCtx(PUT, { id: '123' }),
    );

    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body).toEqual({ message: 'Visite médicale updated successfully', visiteMedicale: { TCS: 'Bob', id_VisiteMedicale: 123, id_salarie: 955 } });
  });
  it('PUT returns 400 when id param is invalid', async () => {
    const res = await PUT(new Request('http://localhost/api/visites-medicales/abc'), makeCtx(PUT, { id: 'abc' }));

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Invalid id parameter');
  });
  it('PUT returns 400 for invalid JSON', async () => {
    const res = await PUT(
      new Request('http://localhost/api/visites-medicales/123', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: '{' }),
      makeCtx(PUT, { id: '123' }),
    );

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Invalid JSON body');
  });

  it('PUT returns 400 when validation fails', async () => {
    const res = await PUT(
      new Request('http://localhost/api/visites-medicales/123', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ id_salarie: 'not-a-number' }) }),
      makeCtx(PUT, { id: '123' }),
    );

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Validation error');
  });
  it('PUT returns auth error when request is unauthorized', async () => {
    // simulate requireAuth returning an HTTP 401 Response
    requireAuthMock.mockReturnValue(new Response('Unauthorized', { status: 401 }));

    const res = await PUT(new Request('http://localhost/api/visites-medicales/1'), makeCtx(PUT, { id: '1' }));

    expect(res.status).toBe(401);
    expect(updateVisiteMedicaleFeedMock).not.toHaveBeenCalled();
    });
  it('PUT returns 404 when VisiteMedicalee not found', async () => {
    updateVisiteMedicaleFeedMock.mockResolvedValue({ visiteMedicale: null });

    const res = await PUT(
      new Request('http://localhost/api/VisiteMedicales/999', { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ TCS: 'Bob' }) }),
      makeCtx(PUT, { id: '999' }),
    );

    expect(res.status).toBe(404);
    const body = await res.json();
    expect(body.message).toBe('Visite médicale not found');
  });

  it('DELETE returns 200 on success', async () => {
    deleteVisiteMedicaleFeedMock.mockResolvedValue({ visiteMedicale: { id_VisiteMedicale: 123, id_salarie: 955 } });

    const res = await DELETE(new Request('http://localhost/api/visites-medicales/123'), makeCtx(DELETE, { id: '123' }));

    expect(res.status).toBe(200);
    const body = await res.json();
    expect(body).toEqual({ message: 'Visite médicale deleted successfully', visiteMedicale: { id_VisiteMedicale: 123, id_salarie: 955 } });
  });
   it('DELETE returns 400 when id param is invalid', async () => {
    const res = await DELETE(new Request('http://localhost/api/visites-medicales/abc'), makeCtx(DELETE, { id: 'abc' }));

    expect(res.status).toBe(400);
    const body = await res.json();
    expect(body.message).toBe('Invalid id parameter');
  });
  it('DELETE returns auth error when request is unauthorized', async () => {
    // simulate requireAuth returning an HTTP 401 Response
    requireAuthMock.mockReturnValue(new Response('Unauthorized', { status: 401 }));

    const res = await DELETE(new Request('http://localhost/api/visites-medicales/1'), makeCtx(DELETE, { id: '1' }));

    expect(res.status).toBe(401);
    expect(deleteVisiteMedicaleFeedMock).not.toHaveBeenCalled();
    });
  it('DELETE returns 404 when not found', async () => {
    deleteVisiteMedicaleFeedMock.mockResolvedValue({ VisiteMedicale: null });

    const res = await DELETE(new Request('http://localhost/api/visites-medicales/999'), makeCtx(DELETE, { id: '999' }));

    expect(res.status).toBe(404);
    const body = await res.json();
    expect(body.message).toBe('Visite médicale not found');
  });
  it('DELETE returns 500 for unknown errors', async () => {
    deleteVisiteMedicaleFeedMock.mockRejectedValue(new Error('boom'));

    const res = await DELETE(new Request('http://localhost/api/visites-medicales/123'), makeCtx(DELETE, { id: '123' }));

    expect(res.status).toBe(500);
    const body = await res.json();
    expect(body.message).toMatch(/Internal Server Error/i);
  });
});
