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

vi.mock('@/services/contrats.service', () => ({
  getContratById: vi.fn(),
  getContratByBusinessId: vi.fn(),
  listContrats: vi.fn(),
  createContrat: vi.fn(),
  updateContratById: vi.fn(),
  deleteContratById: vi.fn(),
}));

vi.mock('@/server/public-entity', () => ({
  toPublicContract: vi.fn((contrat) =>
    contrat ? { ...contrat, public: true } : contrat
  ),
  toPublicContractList: vi.fn((contrats) =>
    contrats.map((contrat: any) => ({ ...contrat, public: true }))
  ),
}));

import {
  getContratById,
  getContratByBusinessId,
  listContrats,
  createContrat,
  updateContratById,
  deleteContratById,
} from '@/services/contrats.service';

import {
  toPublicContract,
  toPublicContractList,
} from '@/server/public-entity';

import {
  getContratsFeed,
  getContratDetails,
  getContratByBusinessIdFeed,
  createContratFeed,
  updateContratFeed,
  deleteContratFeed,
} from '../../../src/server/contrats.server';

describe('Unit - contrats server', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('getContratsFeed returns a public contrats feed', async () => {
    const contrats = [{ id: 1 }, { id: 2 }];

    vi.mocked(listContrats).mockResolvedValue(contrats as never);

    const result = await getContratsFeed(25, 50);

    expect(listContrats).toHaveBeenCalledWith(25, 50);
    expect(toPublicContractList).toHaveBeenCalledWith(contrats);
    expect(result).toEqual({
      items: [
        { id: 1, public: true },
        { id: 2, public: true },
      ],
      count: 2,
    });
  });

  it('getContratDetails returns a public contrat by technical id', async () => {
    const contrat = { id: 1, ID_Contrat: 999 };

    vi.mocked(getContratById).mockResolvedValue(contrat as never);

    const result = await getContratDetails(1);

    expect(getContratById).toHaveBeenCalledWith(1);
    expect(toPublicContract).toHaveBeenCalledWith(contrat);
    expect(result).toEqual({
      contrat: {
        id: 1,
        ID_Contrat: 999,
        public: true,
      },
    });
  });

  it('getContratDetails returns null when contrat does not exist', async () => {
    vi.mocked(getContratById).mockResolvedValue(null as never);

    const result = await getContratDetails(999);

    expect(getContratById).toHaveBeenCalledWith(999);
    expect(toPublicContract).toHaveBeenCalledWith(null);
    expect(result).toEqual({
      contrat: null,
    });
  });

  it('getContratByBusinessIdFeed returns a public contrat by business id', async () => {
    const contrat = { id: 1, ID_Contrat: 999 };

    vi.mocked(getContratByBusinessId).mockResolvedValue(contrat as never);

    const result = await getContratByBusinessIdFeed(999);

    expect(getContratByBusinessId).toHaveBeenCalledWith(999);
    expect(toPublicContract).toHaveBeenCalledWith(contrat);
    expect(result).toEqual({
      contrat: {
        id: 1,
        ID_Contrat: 999,
        public: true,
      },
    });
  });

  it('getContratByBusinessIdFeed returns null when contrat does not exist', async () => {
    vi.mocked(getContratByBusinessId).mockResolvedValue(null as never);

    const result = await getContratByBusinessIdFeed(999);

    expect(getContratByBusinessId).toHaveBeenCalledWith(999);
    expect(toPublicContract).toHaveBeenCalledWith(null);
    expect(result).toEqual({
      contrat: null,
    });
  });

  it('createContratFeed creates and returns a public contrat', async () => {
    const payload = {
      id_salarie: 1937,
      TCS: 'CDI',
      POS: 'Développeur',
    };

    const contrat = {
      id: 1,
      ...payload,
    };

    vi.mocked(createContrat).mockResolvedValue(contrat as never);

    const result = await createContratFeed(payload as any);

    expect(createContrat).toHaveBeenCalledWith(payload);
    expect(toPublicContract).toHaveBeenCalledWith(contrat);
    expect(result).toEqual({
      contrat: {
        id: 1,
        id_salarie: 1937,
        TCS: 'CDI',
        POS: 'Développeur',
        public: true,
      },
    });
  });

  it('updateContratFeed updates and returns a public contrat', async () => {
    const payload = {
      POS: 'Développeur fullstack',
    };

    const contrat = {
      id: 1,
      ID_Contrat: 999,
      POS: 'Développeur fullstack',
    };

    vi.mocked(updateContratById).mockResolvedValue(contrat as never);

    const result = await updateContratFeed(1, payload as any);

    expect(updateContratById).toHaveBeenCalledWith(1, payload);
    expect(toPublicContract).toHaveBeenCalledWith(contrat);
    expect(result).toEqual({
      contrat: {
        id: 1,
        ID_Contrat: 999,
        POS: 'Développeur fullstack',
        public: true,
      },
    });
  });

  it('deleteContratFeed deletes and returns a public contrat', async () => {
    const contrat = {
      id: 1,
      ID_Contrat: 999,
    };

    vi.mocked(deleteContratById).mockResolvedValue(contrat as never);

    const result = await deleteContratFeed(1);

    expect(deleteContratById).toHaveBeenCalledWith(1);
    expect(toPublicContract).toHaveBeenCalledWith(contrat);
    expect(result).toEqual({
      contrat: {
        id: 1,
        ID_Contrat: 999,
        public: true,
      },
    });
  });
});