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

jest.mock('next/link', () => {
  const MockLink = ({children, href}: {children: React.ReactNode; href: string}) => (
    <a href={href}>{children}</a>
  );
  return {__esModule: true, default: MockLink};
});

jest.mock('@/i18n', () =>
  jest.fn().mockResolvedValue({messages: {VilleDetailsPage: {}}})
);

jest.mock('@/services/villeService', () => ({
  getVille: jest.fn(),
  getVilleEvents: jest.fn(),
  getVilleActeurs: jest.fn().mockResolvedValue({total: 0, page: 1, itemsPerPage: 12, items: []}),
}));
jest.mock('@/services/mediaService', () => ({
  getMediaPrincipalUrl: jest.fn().mockResolvedValue(null),
}));
jest.mock('@/components/Ville/ActeursVille', () => ({
  __esModule: true,
  default: ({cible, locale, initial}: {cible: {type: string; id: string}; locale: string; initial: {total: number}}) => (
    <div data-testid="acteurs" data-cible={`${cible.type}:${cible.id}`} data-locale={locale} data-total={initial.total} />
  ),
}));
jest.mock('@/components/Ville/VillePlacesMap', () => ({
  __esModule: true,
  default: ({places}: {places: {plaLibelle: string}[]}) => <div data-testid="places-map" data-count={places.length} />,
}));

jest.mock('@/components/global/CarteLeafletSingleClient', () => ({
  __esModule: true,
  default: () => <div />,
}));
jest.mock('@/components/Evenements/EvenementCardBootstrap/EventCardBootstrap', () => ({
  __esModule: true,
  default: () => <div />,
}));
jest.mock('@/components/Annuaire/AenCardBootstrap/AenCardBootstrap', () => ({
  __esModule: true,
  default: () => <div />,
}));
jest.mock('@/components/community/FavoriteButton', () => ({
  __esModule: true,
  default: ({libelle}: {libelle: string}) => <div data-testid="favorite-button" data-libelle={libelle} />,
}));
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} />
  ),
}));
jest.mock('@/components/Epci/EpciLogoDisplay', () => ({
  __esModule: true,
  default: ({suaNom, suaArticlePartenaire}: {suaNom: string; suaArticlePartenaire?: string}) => (
    <div data-testid="epci-logo" data-article={suaArticlePartenaire}>{suaNom}</div>
  ),
}));

import Page, {generateMetadata} from '../page';
import {getVille, getVilleEvents, getVilleActeurs} from '@/services/villeService';
import {getMediaPrincipalUrl} from '@/services/mediaService';

const mockedGetVille = getVille as jest.Mock;
const mockedGetVilleEvents = getVilleEvents as jest.Mock;
const mockedGetVilleActeurs = getVilleActeurs as jest.Mock;
const mockedGetMediaPrincipalUrl = getMediaPrincipalUrl as jest.Mock;

function ville(subAutres: unknown[]) {
  return {
    vilId: 5,
    vilNom: 'Quimper',
    vilDescription: '',
    vilGeoX: 47.99,
    vilGeoY: -4.1,
    vilGeoZoom: 12,
    vilPay: {payNom: 'France'},
    vilSub1: {subNom: 'Bretagne'},
    vilSub2: {subNom: 'Finistère'},
    places: [],
    subAutres,
  };
}

async function renderPage() {
  const jsx = await (Page as any)({
    params: Promise.resolve({locale: 'fr', vilId: '5'}),
  });
  render(jsx);
}

describe('Ville page — EPCI', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
  });

  it('shouldLinkToTheEpciPage', async () => {
    mockedGetVille.mockResolvedValue(
      ville([{suaId: 3, suaNom: 'Quimper Bretagne Occidentale', suaLogoPartenaire: 1}])
    );

    await renderPage();

    const link = screen.getByRole('link', {name: /intercommunalité/i});
    expect(link).toHaveAttribute('href', '/fr/epci/3/quimper-bretagne-occidentale');
  });

  it('shouldNotLinkToTheEpciPageWithoutPartnerEpci', async () => {
    mockedGetVille.mockResolvedValue(
      ville([{suaId: 3, suaNom: 'Quimper Bretagne Occidentale', suaLogoPartenaire: 0}])
    );

    await renderPage();

    expect(screen.queryByTestId('epci-logo')).not.toBeInTheDocument();
    expect(screen.queryByRole('link', {name: /intercommunalité/i})).not.toBeInTheDocument();
  });
});

describe('Ville page — favoris', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
    mockedGetVille.mockResolvedValue(ville([]));
  });

  it('shouldNameTheVilleInTheFavoriteLoginLink', async () => {
    await renderPage();

    expect(screen.getByTestId('favorite-button')).toHaveAttribute('data-libelle', 'Quimper');
  });
});

describe('Ville page — balise title et compteur de visites', () => {
  const props = {params: Promise.resolve({locale: 'fr', vilId: '5'})};

  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
    mockedGetVille.mockResolvedValue({...ville([]), vilPay: {payCode: 'FR', payNom: 'France'}});
  });

  it('shouldBuildTheDocumentTitleFromTheVilleAndItsDepartement', async () => {
    expect(await generateMetadata(props)).toEqual({title: 'Quimper - Finistère - Tamm-Kreiz'});
  });

  it('shouldFallBackToTheSiteNameWhenTheVilleCannotBeLoaded', async () => {
    mockedGetVille.mockRejectedValue(new Error('HTTP 404'));

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

  it('shouldCountTheVisitsOfTheVille', async () => {
    await renderPage();

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

describe('Ville page — lien article du bloc EPCI', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
  });

  it('shouldPassTheArticleLinkToThePartnerEpciBlock', async () => {
    mockedGetVille.mockResolvedValue(
      ville([{suaId: 3, suaNom: 'Quimper Bretagne Occidentale', suaLogoPartenaire: 1, suaArticlePartenaire: 'https://www.tamm-kreiz.bzh/mag/territoires'}])
    );

    await renderPage();

    expect(screen.getByTestId('epci-logo')).toHaveAttribute('data-article', 'https://www.tamm-kreiz.bzh/mag/territoires');
  });

});

describe('Ville page — agenda, lieux et acteurs', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
    mockedGetVilleActeurs.mockResolvedValue({total: 0, page: 1, itemsPerPage: 12, items: []});
    mockedGetMediaPrincipalUrl.mockResolvedValue(null);
    mockedGetVille.mockResolvedValue(ville([]));
  });

  it('shouldSayNoUpcomingEventAndStillLinkToTheFilteredAgenda', async () => {
    await renderPage();

    // Les messages du test sont vides : la page affiche ses textes de repli.
    expect(screen.getByText('Aucun événement à venir')).toBeInTheDocument();
    const lien = screen.getByRole('link', {name: /Tous les événements à Quimper/});
    expect(lien).toHaveAttribute('href', '/fr/evenements?ville=5&villeName=Quimper');
  });

  it('shouldShowThePlacesWithTheirPhotoAndMapThem', async () => {
    mockedGetVille.mockResolvedValue({
      ...ville([]),
      places: [
        {plaId: 1, plaLibelle: 'Salle du Chapeau Rouge', plaAdresse1: '1 rue du Paradis', plaAdresse2: '', plaCodepostal: '29000', plaGeoX: 47.995, plaGeoY: -4.11},
        {plaId: 2, plaLibelle: 'Salle des fêtes', plaAdresse1: '', plaAdresse2: '', plaCodepostal: '', plaGeoX: null, plaGeoY: null},
      ],
    });
    mockedGetMediaPrincipalUrl.mockImplementation((_type: string, id: number) => Promise.resolve(id === 1 ? 'https://media.test/chapeau.jpg' : null));

    await renderPage();

    expect(mockedGetMediaPrincipalUrl).toHaveBeenCalledWith('geolocale_place', 1, expect.anything());
    expect(screen.getByRole('img', {name: 'Salle du Chapeau Rouge'})).toHaveAttribute('src', 'https://media.test/chapeau.jpg');
    expect(screen.getByTestId('places-map')).toHaveAttribute('data-count', '2');
  });

  it('shouldMountTheActorsBlockWithTheFirstPage', async () => {
    mockedGetVilleActeurs.mockResolvedValue({total: 48, page: 1, itemsPerPage: 12, items: [{aenId: 1, aenLibelle: 'Bagad', actif: true, photoUrl: null, type: 'groupe', cibleId: 9, listes: []}]});

    await renderPage();

    expect(mockedGetVilleActeurs).toHaveBeenCalledWith('5');
    const acteurs = screen.getByTestId('acteurs');
    expect(acteurs).toHaveAttribute('data-total', '48');
    expect(acteurs).toHaveAttribute('data-locale', 'fr');
  });
});

describe('Ville page — région et département (spec L156)', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetVilleEvents.mockResolvedValue([]);
  });

  it('shouldLinkTheRegionAndTheDepartmentOfAFrenchTown', async () => {
    mockedGetVille.mockResolvedValue({...ville([]), vilPay: {payNom: 'France', payCode: 'FR'}, vilSub1: {subId: 12, subNom: 'Bretagne'}, vilSub2: {subId: 29, subNom: 'Finistère'}});

    await renderPage();

    expect(screen.getByRole('link', {name: 'Bretagne'})).toHaveAttribute('href', '/fr/region/12/bretagne');
    expect(screen.getByRole('link', {name: 'Finistère'})).toHaveAttribute('href', '/fr/departement/29/finistere');
  });

  it('shouldKeepPlainNamesOutsideFrance', async () => {
    mockedGetVille.mockResolvedValue({...ville([]), vilPay: {payNom: 'Irlande', payCode: 'IE'}, vilSub1: {subId: 3, subNom: 'Connacht'}, vilSub2: {subId: 4, subNom: 'Galway'}});

    await renderPage();

    expect(screen.getByText('Connacht')).toBeInTheDocument();
    expect(screen.queryByRole('link', {name: 'Connacht'})).not.toBeInTheDocument();
    expect(screen.queryByRole('link', {name: 'Galway'})).not.toBeInTheDocument();
  });
});
