import React from 'react';
import {fireEvent, render, screen, waitFor} from '@testing-library/react';

jest.mock('next-intl', () => ({
  useTranslations: () => (key: string, values?: Record<string, unknown>) => (values ? `${key}:${JSON.stringify(values)}` : key),
}));
jest.mock('@/services/propositionService', () => ({
  getCaptcha: jest.fn(),
  envoyerProposition: jest.fn(),
}));
jest.mock('../AsyncMultiSelectAen/AsyncMultiSelectAen', () => ({
  __esModule: true,
  default: ({onSelectionChange, defaultValue}: {onSelectionChange: (s: unknown[]) => void; defaultValue?: {value: number; label: string}[]}) => (
    <div data-testid="select-aen" data-default={JSON.stringify(defaultValue ?? [])}>
      <button type="button" onClick={() => onSelectionChange([{value: 5, label: 'Bagad Kemper'}])}>choisir-bagad</button>
    </div>
  ),
}));

import PropositionEvenementForm from '../PropositionEvenementForm';
import {envoyerProposition, getCaptcha} from '@/services/propositionService';

const typeEvents = [
  {tevId: 1, tevLibelle: 'Fest-noz', tevDpr: {dprNom: 'Musique'}},
  {tevId: 4, tevLibelle: 'Stage', tevDpr: {dprNom: 'Formation'}},
];

const initialValues = {
  tevId: 4,
  date: '2030-05-01',
  heure: '20h30',
  lieu: 'Salle de la Cité, Rennes',
  lieuDesc: '10 rue Saint-Louis',
  prix: '7 €',
  description: 'Grand fest-noz',
  url: 'https://billets.bzh',
  artistesDesc: '',
  participants: [{value: 5, label: 'Bagad Kemper'}],
};

function champ<T extends HTMLElement>(container: HTMLElement, id: string): T {
  const element = container.querySelector<T>(`#${id}`);
  if (!element) throw new Error(`champ ${id} introuvable`);
  return element;
}

function remplirContact(container: HTMLElement) {
  fireEvent.change(champ(container, 'yourMailInputForm'), {target: {value: 'anna@exemple.bzh'}});
  fireEvent.change(champ(container, 'yourNameInputForm'), {target: {value: 'Anna'}});
  fireEvent.change(champ(container, 'yourPhoneNumberInputForm'), {target: {value: '0612345678'}});
  fireEvent.change(champ(container, 'captchaInputForm'), {target: {value: '5'}});
}

describe('PropositionEvenementForm', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    (getCaptcha as jest.Mock).mockResolvedValue({token: 'jeton', question: 'Combien font 2 + 3 ?'});
    (envoyerProposition as jest.Mock).mockResolvedValue({ok: true, message: 'Merci', eprId: 12, erreurs: {}});
  });

  it('shouldAskTheCaptchaQuestion', async () => {
    render(<PropositionEvenementForm typeEvents={typeEvents} />);

    expect(await screen.findByText(/Combien font 2 \+ 3/)).toBeInTheDocument();
  });

  it('shouldRefuseToSendWhenRequiredFieldsAreMissing', async () => {
    const {container} = render(<PropositionEvenementForm typeEvents={typeEvents} />);
    await screen.findByText(/Combien font 2 \+ 3/);

    fireEvent.click(screen.getByRole('button', {name: 'submit'}));

    expect(envoyerProposition).not.toHaveBeenCalled();
    expect(screen.getByText('where_form_error')).toBeInTheDocument();
    expect(screen.getByText('plateau_form_error')).toBeInTheDocument();
    expect(screen.getByText('captcha_form_error')).toBeInTheDocument();
    expect(container.querySelector('#descriptionEventForm')).not.toHaveClass('is-invalid');
  });

  it('shouldSendTheProposalAndConfirm', async () => {
    const {container} = render(<PropositionEvenementForm typeEvents={typeEvents} />);
    await screen.findByText(/Combien font 2 \+ 3/);
    fireEvent.change(champ(container, 'whenInputDateForm'), {target: {value: '2030-05-01'}});
    fireEvent.change(champ(container, 'whereInputForm'), {target: {value: 'Salle des fêtes'}});
    fireEvent.change(champ(container, 'priceInputForm'), {target: {value: '7 €'}});
    fireEvent.change(champ(container, 'descriptionEventForm'), {target: {value: 'Une belle soirée'}});
    fireEvent.change(champ(container, 'anotherWebsiteEventForm'), {target: {value: 'https://exemple.bzh'}});
    fireEvent.click(screen.getByText('choisir-bagad'));
    remplirContact(container);

    fireEvent.click(screen.getByRole('button', {name: 'submit'}));

    await waitFor(() => expect(envoyerProposition).toHaveBeenCalledTimes(1));
    const formData: FormData = (envoyerProposition as jest.Mock).mock.calls[0][0];
    expect(formData.get('eprTev')).toBe('1');
    expect(formData.get('eprDate')).toBe('2030-05-01');
    expect(formData.get('eprHeure')).toBe('21h00');
    expect(formData.get('eprLieu')).toBe('Salle des fêtes');
    expect(formData.get('eprDescription')).toBe('Une belle soirée');
    expect(formData.get('eprUrl')).toBe('https://exemple.bzh');
    expect(formData.get('aenParticipants[0]')).toBe('5');
    expect(formData.get('captchaToken')).toBe('jeton');
    expect(formData.get('captchaReponse')).toBe('5');
    expect(formData.get('eprModif')).toBeNull();
    expect(await screen.findByRole('status')).toHaveTextContent('success_message');
    expect(screen.queryByRole('button', {name: 'submit'})).not.toBeInTheDocument();
  });

  it('shouldPrefillAndFlagAModification', async () => {
    const {container} = render(
      <PropositionEvenementForm typeEvents={typeEvents} mode="modification" evenementId={72} evenementHref="/fr/evenement/72/fest-noz" initialValues={initialValues} />
    );
    await screen.findByText(/Combien font 2 \+ 3/);

    expect(champ<HTMLSelectElement>(container, 'whatInputForm').value).toBe('4');
    expect(champ<HTMLInputElement>(container, 'whenInputDateForm').value).toBe('2030-05-01');
    expect(champ<HTMLSelectElement>(container, 'WhenInputHourForm').value).toBe('20h30');
    expect(champ<HTMLInputElement>(container, 'whereInputForm').value).toBe('Salle de la Cité, Rennes');
    expect(champ<HTMLTextAreaElement>(container, 'descriptionEventForm').value).toBe('Grand fest-noz');
    expect(screen.getByTestId('select-aen')).toHaveAttribute('data-default', JSON.stringify(initialValues.participants));
    remplirContact(container);

    fireEvent.click(screen.getByRole('button', {name: 'submit'}));

    await waitFor(() => expect(envoyerProposition).toHaveBeenCalledTimes(1));
    const formData: FormData = (envoyerProposition as jest.Mock).mock.calls[0][0];
    expect(formData.get('eprModif')).toBe('1');
    expect(formData.get('eprEve')).toBe('72');
    expect(formData.get('aenParticipants[0]')).toBe('5');
    expect(await screen.findByRole('status')).toHaveTextContent('success_modification');
    expect(screen.getByRole('link', {name: 'back_to_event'})).toHaveAttribute('href', '/fr/evenement/72/fest-noz');
  });

  it('shouldShowServerErrorsAndRenewTheCaptcha', async () => {
    (envoyerProposition as jest.Mock).mockResolvedValue({ok: false, message: 'Le formulaire comporte des erreurs.', erreurs: {captcha: 'Mauvaise réponse', plateau: 'Groupe requis'}});
    const {container} = render(
      <PropositionEvenementForm typeEvents={typeEvents} mode="modification" evenementId={72} initialValues={initialValues} />
    );
    await screen.findByText(/Combien font 2 \+ 3/);
    remplirContact(container);

    fireEvent.click(screen.getByRole('button', {name: 'submit'}));

    expect(await screen.findByRole('alert')).toHaveTextContent('Le formulaire comporte des erreurs.');
    expect(screen.getByText('Mauvaise réponse')).toBeInTheDocument();
    expect(screen.getByText('Groupe requis')).toBeInTheDocument();
    await waitFor(() => expect(getCaptcha).toHaveBeenCalledTimes(2));
  });

  it('shouldExplainWhenTheCaptchaIsUnavailable', async () => {
    (getCaptcha as jest.Mock).mockResolvedValue(null);
    render(<PropositionEvenementForm typeEvents={typeEvents} />);

    expect(await screen.findByText('captcha_unavailable')).toBeInTheDocument();
  });
});
