import http, {HttpError} from '@/http';
import {envoyerProposition, getCaptcha, initialValuesFromEvenement} from './propositionService';

// Le mock global (setupTests) ne fournit que le client : on garde la vraie classe d'erreur.
jest.mock('@/http', () => ({
  __esModule: true,
  default: {get: jest.fn(), post: jest.fn()},
  HttpError: jest.requireActual('@/http').HttpError,
}));

const mockGet = http.get as jest.Mock;
const mockPost = http.post as jest.Mock;

describe('propositionService', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('shouldFetchACaptchaChallenge', async () => {
    mockGet.mockResolvedValue({data: {token: 'abc', question: 'Combien font 2 + 3 ?'}});

    const captcha = await getCaptcha();

    expect(mockGet).toHaveBeenCalledWith('/captcha');
    expect(captcha).toEqual({token: 'abc', question: 'Combien font 2 + 3 ?'});
  });

  it('shouldReturnNullWhenTheCaptchaCannotBeFetched', async () => {
    mockGet.mockRejectedValue(new Error('réseau'));

    expect(await getCaptcha()).toBeNull();
  });

  it('shouldPostTheFormDataAndReportSuccess', async () => {
    mockPost.mockResolvedValue({data: {status: 'success', message: 'Merci', eprId: 12, afficheEnregistree: false}, status: 201});
    const formData = new FormData();

    const resultat = await envoyerProposition(formData);

    expect(mockPost).toHaveBeenCalledWith('/evenement_propositions', formData);
    expect(resultat).toEqual({ok: true, message: 'Merci', eprId: 12, erreurs: {}});
  });

  it('shouldSurfaceFieldErrorsOnValidationFailure', async () => {
    mockPost.mockRejectedValue(new HttpError(422, {status: 'error', message: 'Le formulaire comporte des erreurs.', erreurs: {captcha: 'Mauvaise réponse', plateau: 'Groupe requis'}}));

    const resultat = await envoyerProposition(new FormData());

    expect(resultat.ok).toBe(false);
    expect(resultat.erreurs).toEqual({captcha: 'Mauvaise réponse', plateau: 'Groupe requis'});
    expect(resultat.message).toBe('Le formulaire comporte des erreurs.');
  });

  it('shouldReportAGenericFailureOnOtherErrors', async () => {
    mockPost.mockRejectedValue(new Error('réseau'));

    const resultat = await envoyerProposition(new FormData());

    expect(resultat).toEqual({ok: false, message: '', erreurs: {}});
  });

  it('shouldMapAnEventToTheFormInitialValues', () => {
    const valeurs = initialValuesFromEvenement({
      eveId: 72,
      eveDate: '2026-09-20T00:00:00+02:00',
      eveHeure: '21:30',
      eveLibelle: 'Grand fest-noz',
      evePrixLibelle: '7 €',
      eveHorsBase: 'Les Frères Morvan',
      eveUrlReservation: 'https://billets.bzh',
      eveTev: {tevId: 1, tevLibelle: 'Fest-noz'},
      eveVil: {vilNom: 'Rennes'},
      evePla: {plaNom: 'Salle de la Cité', plaAdresse: '10 rue Saint-Louis'},
      aenParticipants: [{aenId: 5, aenLibelle: 'Bagad Kemper'}, {aenId: 6, aenLibelle: 'Startijenn'}],
    });

    expect(valeurs).toEqual({
      tevId: 1,
      date: '2026-09-20',
      heure: '21h30',
      lieu: 'Salle de la Cité, Rennes',
      lieuDesc: '10 rue Saint-Louis',
      prix: '7 €',
      description: 'Grand fest-noz',
      url: 'https://billets.bzh',
      artistesDesc: 'Les Frères Morvan',
      participants: [{value: 5, label: 'Bagad Kemper'}, {value: 6, label: 'Startijenn'}],
    });
  });

  it('shouldFallBackToTheCityWhenTheEventHasNoPlace', () => {
    const valeurs = initialValuesFromEvenement({eveId: 1, eveDate: '2026-10-01', eveVil: {vilNom: 'Vannes'}, aenParticipants: []});

    expect(valeurs.lieu).toBe('Vannes');
    expect(valeurs.heure).toBe('');
    expect(valeurs.tevId).toBeUndefined();
    expect(valeurs.participants).toEqual([]);
  });
});
