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

const mockedGet = jest.fn();
jest.mock('@/http', () => ({
  __esModule: true,
  default: {get: (...args: unknown[]) => mockedGet(...args)},
  HttpError: class HttpError extends Error {
    status: number;
    constructor(status: number) {
      super(`HTTP ${status}`);
      this.status = status;
    }
  },
}));
jest.mock('next-intl', () => ({
  NextIntlClientProvider: ({children}: {children: React.ReactNode}) => <>{children}</>,
  useTranslations: () => (key: string) => key,
}));
jest.mock('next/link', () => ({
  __esModule: true,
  default: ({children, href}: {children: React.ReactNode; href: string}) => <a href={href}>{children}</a>,
}));
jest.mock('@/i18n', () => jest.fn().mockResolvedValue({messages: {}}));
jest.mock('@/services/epciService', () => ({
  findEpciWithLogo: (subAutres?: {suaLogoPartenaire: number}[]) => subAutres?.find(s => s.suaLogoPartenaire === 1) ?? null,
}));

jest.mock('@/components/Evenements/EvenementDetails/CardInfoAffiche/CardInfoAffiche', () => ({__esModule: true, default: () => <div data-testid="affiche" />}));
jest.mock('@/components/Evenements/EvenementDetails/Lieux/Lieu', () => ({
  __esModule: true,
  default: ({parking, parquet, capacity, photoUrl, stations, avecCaracteristiques}: {parking: boolean; parquet: boolean; capacity: number | null; photoUrl?: string | null; stations?: string[]; avecCaracteristiques?: boolean}) => (
    <div data-testid="lieu" data-parking={String(parking)} data-parquet={String(parquet)} data-capacity={capacity ?? ''} data-photo={photoUrl ?? ''} data-stations={(stations ?? []).join('|')} data-caracteristiques={String(avecCaracteristiques ?? true)} />
  ),
}));
jest.mock('next/navigation', () => ({
  notFound: jest.fn(() => {
    throw new Error('NOT_FOUND');
  }),
  redirect: jest.fn((url: string) => {
    throw new Error(`REDIRECT:${url}`);
  }),
}));
jest.mock('@/components/shared/VoirAussiEnsembles/VoirAussiEnsembles', () => ({
  __esModule: true,
  default: ({ensembles, currentEveId}: {ensembles: {eesLibelle: string; logoUrl: string | null; evenements: unknown[]}[]; currentEveId: number}) => (
    <div data-testid="voir-aussi" data-current={currentEveId}>{ensembles.map(e => `${e.eesLibelle}:${e.logoUrl ?? ''}:${e.evenements.length}`).join('|')}</div>
  ),
}));
jest.mock('@/components/shared/AnimateursGallery/AnimateursGallery', () => ({
  __esModule: true,
  default: ({animateurs, titleKey}: {animateurs: {aenId: number; photoUrl: string | null; href?: string}[]; titleKey?: string}) => (
    <div data-testid="galerie" data-title={titleKey ?? ''}>{animateurs.map(a => `${a.aenId}:${a.photoUrl ?? ''}:${a.href ?? ''}`).join('|')}</div>
  ),
}));
jest.mock('@/components/shared/FichiersSection/FichiersSection', () => ({
  __esModule: true,
  default: ({fichiers}: {fichiers: unknown[]}) => <div data-testid="fichiers" data-count={fichiers.length} />,
}));
jest.mock('@/services/mediaService', () => ({
  getMediaPrincipalUrl: jest.fn().mockResolvedValue(null),
  getLogoUrl: jest.fn().mockResolvedValue(null),
}));
jest.mock('@/services/ensembleEvenementService', () => ({
  getEnsembleEvenementFront: jest.fn().mockResolvedValue(null),
}));
jest.mock('@/services/entityFilesService', () => ({
  getFichiers: jest.fn().mockResolvedValue([]),
}));
jest.mock('@/components/Evenements/EvenementDetails/OrgaInfo/ColonneOrgaInfo', () => ({__esModule: true, default: () => <div data-testid="orga" />}));
jest.mock('@/components/Evenements/EvenementDetails/PartageSocialDiv/PartageSocialDiv', () => ({__esModule: true, default: () => <div data-testid="partage" />}));
jest.mock('@/components/Evenements/EvenementDetails/Programme/Programme', () => ({__esModule: true, default: () => <div data-testid="programme" />}));
jest.mock('@/components/Epci/EpciLogoDisplay', () => ({
  __esModule: true,
  default: ({suaArticlePartenaire}: {suaArticlePartenaire?: string}) => <div data-testid="epci-logo" data-article={suaArticlePartenaire} />,
}));
jest.mock('@/components/community/CommentSection', () => ({__esModule: true, default: () => <div data-testid="comments" />}));
jest.mock('@/components/community/CarpoolSection', () => ({__esModule: true, default: ({evenementId}: {evenementId: number}) => <div data-testid="carpool" data-eve={evenementId} />}));
jest.mock('@/components/community/ParticipationButton', () => ({__esModule: true, default: () => <div data-testid="participation" />}));
jest.mock('@/components/community/ParticipantSection', () => ({__esModule: true, default: () => <div data-testid="participants" />}));
jest.mock('@/components/community/FavoriteButton', () => ({__esModule: true, default: () => <div data-testid="favorite" />}));
jest.mock('@/services/articleLienService', () => ({
  getArticlesLies: jest.fn().mockResolvedValue([]),
}));
jest.mock('@/components/shared/ArticlesLiesSection/ArticlesLiesSection', () => ({
  __esModule: true,
  default: ({articles, locale}: {articles?: unknown[]; locale: string}) => (
    <div data-testid="articles-lies" data-count={articles?.length ?? 0} data-locale={locale} />
  ),
}));
jest.mock('@/components/shared/VisitCounter/VisitCounter', () => ({
  __esModule: true,
  default: ({tableCible, cibleId}: {tableCible: string; cibleId: number}) => (
    <div data-testid="visit-counter" data-table={tableCible} data-cible={cibleId} />
  ),
}));

import Page, {generateMetadata} from '../page';
import {getLogoUrl, getMediaPrincipalUrl} from '@/services/mediaService';
import {getEnsembleEvenementFront} from '@/services/ensembleEvenementService';
import {getFichiers} from '@/services/entityFilesService';

const mockedGetMediaPrincipalUrl = getMediaPrincipalUrl as jest.Mock;
const mockedGetLogoUrl = getLogoUrl as jest.Mock;
const mockedGetEnsembleFront = getEnsembleEvenementFront as jest.Mock;
const mockedGetFichiers = getFichiers as jest.Mock;
import {getArticlesLies} from '@/services/articleLienService';

const mockedGetArticlesLies = getArticlesLies as jest.Mock;

const props = {params: Promise.resolve({locale: 'fr', eventId: '72'})};

const festNoz = {
  eveId: 72,
  eveDate: '2026-09-20',
  eveHeure: '21:00',
  eveLibelle: '',
  evePrixLibelle: '',
  evePrixPleinTarif: null,
  evePla: null,
  eveTev: {tevLibelle: 'Fest-noz'},
  eveVil: {vilNom: 'Rennes', vilCodepostal: '35000', vilGeoX: 48.1, vilGeoY: -1.7, vilGeoZoom: 12, subAutres: []},
  aenOrganisateurs: [],
  aenParticipants: [],
  ensembles: [],
};

function serveEvent(event: unknown) {
  mockedGet.mockImplementation((url: string) =>
    url.startsWith('/media/')
      ? Promise.resolve({data: {url: null}})
      : Promise.resolve({data: event})
  );
}

describe('Page événement — titre et compteur de vues', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    serveEvent(festNoz);
  });

  it('shouldBuildTheDocumentTitleFromTypeVilleAndDate', async () => {
    expect(await generateMetadata(props)).toEqual({title: 'Fest-noz à Rennes, dimanche 20 septembre 2026 - Tamm-Kreiz'});
  });

  it('shouldFallBackToTheSiteNameWhenTheEventCannotBeLoaded', async () => {
    mockedGet.mockRejectedValue(new Error('HTTP 500'));

    expect(await generateMetadata(props)).toEqual({title: 'Tamm-Kreiz'});
  });

  it('shouldPutTheDateInTheHeading', async () => {
    render(await (Page as any)(props));

    expect(screen.getByRole('heading', {level: 1})).toHaveTextContent('Fest-noz à Rennes, dimanche 20 septembre 2026');
  });

  it('shouldCountTheViewsOfTheEvent', async () => {
    render(await (Page as any)(props));

    const counter = screen.getByTestId('visit-counter');
    expect(counter).toHaveAttribute('data-table', 'evenement');
    expect(counter).toHaveAttribute('data-cible', '72');
  });
});

describe('Page événement — lien article du bloc EPCI', () => {
  it('shouldPassTheArticleLinkToThePartnerEpciBlock', async () => {
    const qbo = {suaId: 3, suaNom: 'QBO', suaLogoPartenaire: 1, suaArticlePartenaire: 'https://www.tamm-kreiz.bzh/mag/territoires'};
    serveEvent({...festNoz, eveVil: {...festNoz.eveVil, subAutres: [qbo]}});

    render(await (Page as any)(props));

    expect(screen.getByTestId('epci-logo')).toHaveAttribute('data-article', qbo.suaArticlePartenaire);
  });
});

describe('Page événement — articles du Mag', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    serveEvent(festNoz);
    mockedGetArticlesLies.mockResolvedValue([{id: 1, title: 'Les sonneurs de couple', slug: 'sonneurs-de-couple'}]);
  });

  it('shouldListTheArticlesLinkedToTheEvent', async () => {
    render(await (Page as any)(props));

    expect(mockedGetArticlesLies).toHaveBeenCalledWith('evenement', '72');
    const section = screen.getByTestId('articles-lies');
    expect(section).toHaveAttribute('data-count', '1');
    expect(section).toHaveAttribute('data-locale', 'fr');
  });
});

describe('Page événement — infos pratiques', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('shouldOfferToProposeAModification', async () => {
    render(await (Page as any)(props));

    expect(screen.getByRole('link', {name: /complément d'info/i})).toHaveAttribute('href', '/fr/modification/72');
  });

  it('shouldLinkToTheBookingUrl', async () => {
    serveEvent({...festNoz, eveUrlReservation: 'https://billetterie.example/fest-noz'});

    render(await (Page as any)(props));

    expect(screen.getByRole('link', {name: /réserver/i})).toHaveAttribute('href', 'https://billetterie.example/fest-noz');
  });

  it('shouldStripTheHtmlOfTheDescription', async () => {
    serveEvent({...festNoz, eveLibelle: 'Grand fest-noz<br>avec <b>Sonerien Du</b>'});

    render(await (Page as any)(props));

    const description = screen.getByTestId('event-description');
    expect(description).toHaveTextContent('Grand fest-noz');
    expect(description).toHaveTextContent('avec Sonerien Du');
    expect(description.innerHTML).not.toContain('<b>');
    expect(description.innerHTML).not.toContain('&lt;br&gt;');
  });

  it('shouldShowThePriceLabelEvenWithoutAFullPrice', async () => {
    serveEvent({...festNoz, evePrixLibelle: 'Prix libre', evePrixPleinTarif: null});

    render(await (Page as any)(props));

    expect(screen.getByTestId('event-prix')).toHaveTextContent('Prix libre');
  });

  it('shouldRedirectToTheHomePageWhenTheEventIsNotValid', async () => {
    serveEvent({...festNoz, eveValide: 0});

    await expect((Page as any)(props)).rejects.toThrow('REDIRECT:/fr');
  });
});

describe('Page événement — lieu, voir aussi, programmés, fichiers, covoiturage', () => {
  const salle = {plaId: 77, plaLibelle: 'Salle des fêtes', plaCapacite: 250, plaParking: 1, plaParquet: 0, plaGeoX: 48.1, plaGeoY: -1.7, plaGeoZoom: 14,
    stations: [{gtsId: 1, gtsNom: 'Gare de Rennes'}, {gtsId: 2, gtsNom: 'République'}]};
  const programmes = [
    {aenId: 2025, aenLibelle: 'BAROU Sylvain', aenMorale: 0, aenFmu: []},
    {aenId: 12, aenLibelle: 'Bagad Kemper', aenMorale: 1, aenFmu: [{fmuId: 5}]},
    {aenId: 42, aenLibelle: 'Cercle de Rennes', aenMorale: 1, aenFmu: [], aenEns: [{ensId: 7}]},
  ];

  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetMediaPrincipalUrl.mockImplementation((type: string, id: number) =>
      Promise.resolve(type === 'geolocale_place' ? 'https://media.tamm-kreiz.bzh/salle.jpg' : id === 2025 ? 'https://media.tamm-kreiz.bzh/barou.jpg' : null)
    );
    mockedGetLogoUrl.mockResolvedValue('https://media.tamm-kreiz.bzh/fil.png');
    mockedGetEnsembleFront.mockResolvedValue({eesId: 5, eesLibelle: 'Festival Interceltique', evenements: [{eveId: 72, eveDate: '2026-09-20'}, {eveId: 73, eveDate: '2026-09-21'}]});
    mockedGetFichiers.mockResolvedValue([{medId: 1, url: 'https://media.tamm-kreiz.bzh/programme.pdf', filename: 'programme.pdf', label: 'Programme', mimetype: 'application/pdf', source: 'own'}]);
  });

  it('shouldDescribeThePlaceWithRealFeaturesPhotoAndStations', async () => {
    serveEvent({...festNoz, evePla: salle});

    render(await (Page as any)(props));

    const lieu = screen.getByTestId('lieu');
    expect(lieu).toHaveAttribute('data-parking', 'true');
    expect(lieu).toHaveAttribute('data-parquet', 'false');
    expect(lieu).toHaveAttribute('data-capacity', '250');
    expect(lieu).toHaveAttribute('data-photo', 'https://media.tamm-kreiz.bzh/salle.jpg');
    expect(lieu).toHaveAttribute('data-stations', 'Gare de Rennes|République');
    expect(lieu).toHaveAttribute('data-caracteristiques', 'true');
  });

  it('shouldOnlyNameTheCityWithoutPlace', async () => {
    serveEvent(festNoz);

    render(await (Page as any)(props));

    expect(screen.getByTestId('lieu')).toHaveAttribute('data-caracteristiques', 'false');
    expect(mockedGetMediaPrincipalUrl).not.toHaveBeenCalledWith('geolocale_place', expect.anything(), expect.anything());
  });

  it('shouldListTheEnsemblesWithLogoAndSiblingEvents', async () => {
    serveEvent({...festNoz, ensembles: [{eesId: 5, eesLibelle: 'Festival Interceltique'}]});

    render(await (Page as any)(props));

    const voirAussi = screen.getByTestId('voir-aussi');
    expect(voirAussi).toHaveAttribute('data-current', '72');
    expect(voirAussi).toHaveTextContent('Festival Interceltique:https://media.tamm-kreiz.bzh/fil.png:2');
  });

  it('shouldShowTheGalleryOfPerformersWithTheirOwnLinks', async () => {
    serveEvent({...festNoz, aenParticipants: programmes, eveHorsBase: 'Les Ramoneurs de Menhirs'});

    render(await (Page as any)(props));

    const galerie = screen.getByTestId('galerie');
    expect(galerie).toHaveAttribute('data-title', 'programmes_title');
    expect(galerie).toHaveTextContent('2025:https://media.tamm-kreiz.bzh/barou.jpg:/fr/personne/2025/barou-sylvain|12::/fr/groupes/5|42::/fr/ensembles-traditionnels/7');
    expect(screen.getByTestId('hors-base')).toHaveTextContent('Les Ramoneurs de Menhirs');
  });

  it('shouldOfferTheAttachedFiles', async () => {
    serveEvent(festNoz);

    render(await (Page as any)(props));

    expect(screen.getByTestId('fichiers')).toHaveAttribute('data-count', '1');
    expect(mockedGetFichiers).toHaveBeenCalledWith('evenement', '72');
  });

  it('shouldOnlyOfferCarpoolOnAnUpcomingEvent', async () => {
    serveEvent({...festNoz, eveDate: '2020-09-20'});
    const {unmount} = render(await (Page as any)(props));
    expect(screen.queryByTestId('carpool')).not.toBeInTheDocument();
    unmount();

    serveEvent({...festNoz, eveDate: '2099-09-20'});
    render(await (Page as any)(props));
    expect(screen.getByTestId('carpool')).toHaveAttribute('data-eve', '72');
  });
});
