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

const mockAuth: {isAuthenticated: boolean; loading: boolean; user: {id: string; username: string} | null} = {isAuthenticated: false, loading: false, user: null};
jest.mock('@/contexts/AuthContext', () => ({useAuth: () => mockAuth}));
jest.mock('next-intl', () => ({
  useTranslations: () => (key: string, values?: Record<string, unknown>) => (values ? `${key}:${Object.values(values).join('/')}` : key),
}));
jest.mock('next/link', () => ({
  __esModule: true,
  default: ({children, href, ...rest}: {children: React.ReactNode; href: string}) => <a href={href} {...rest}>{children}</a>,
}));
jest.mock('@/services/annonceService', () => ({
  getAnnonceTypes: jest.fn(),
  getAnnonces: jest.fn(),
  createAnnonce: jest.fn(),
  updateAnnonce: jest.fn(),
  deleteAnnonce: jest.fn(),
  repondreAnnonce: jest.fn(),
}));

import AnnoncesBoard from '../AnnoncesBoard';
import {createAnnonce, deleteAnnonce, getAnnonces, getAnnonceTypes, repondreAnnonce, updateAnnonce} from '@/services/annonceService';

const types = [{id: 1, titre: 'Instruments', soustitre: 'Achat/vente'}, {id: 2, titre: 'Cours', soustitre: 'Donne ou cherche'}];
const annonces = [
  {id: 7, titre: 'Vends bombarde', texte: 'Très bon état', date: '2026-09-16', typeId: 1, auteur: {id: 3, pseudo: 'anna'}},
  {id: 8, titre: 'Cherche prof de biniou', texte: null, date: '2026-09-10', typeId: 2, auteur: {id: 4, pseudo: 'yann'}},
];

function connecte(username: string) {
  mockAuth.isAuthenticated = true;
  mockAuth.user = {id: '9', username};
}

describe('AnnoncesBoard', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockAuth.isAuthenticated = false;
    mockAuth.user = null;
    (getAnnonceTypes as jest.Mock).mockResolvedValue(types);
    (getAnnonces as jest.Mock).mockResolvedValue(annonces);
    window.confirm = jest.fn(() => true);
  });

  it('shouldListTheAdsAndInviteVisitorsToLogInToReplyOrPost', async () => {
    render(<AnnoncesBoard locale="fr" />);

    expect(await screen.findByText('Vends bombarde')).toBeInTheDocument();
    expect(screen.getByText('Cherche prof de biniou')).toBeInTheDocument();
    const invitations = screen.getAllByRole('link', {name: 'login_to_reply'});
    expect(invitations).toHaveLength(2);
    expect(invitations[0]).toHaveAttribute('href', '/fr/connexion');
    expect(screen.getByRole('link', {name: 'login_to_post'})).toHaveAttribute('href', '/fr/connexion');
    expect(screen.queryByRole('button', {name: 'create'})).not.toBeInTheDocument();
  });

  it('shouldFilterTheAdsByType', async () => {
    render(<AnnoncesBoard locale="fr" />);
    await screen.findByText('Vends bombarde');

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

    await waitFor(() => expect(getAnnonces).toHaveBeenLastCalledWith(2));
  });

  it('shouldLetAMemberReplyToSomeoneElsesAd', async () => {
    connecte('soazig');
    (repondreAnnonce as jest.Mock).mockResolvedValue(undefined);
    render(<AnnoncesBoard locale="fr" />);
    const carte = (await screen.findByText('Vends bombarde')).closest('article') as HTMLElement;

    fireEvent.click(within(carte).getByRole('button', {name: 'reply'}));
    fireEvent.change(within(carte).getByPlaceholderText('reply_placeholder'), {target: {value: "J'ai une bombarde"}});
    fireEvent.click(within(carte).getByRole('button', {name: 'reply_send'}));

    await waitFor(() => expect(repondreAnnonce).toHaveBeenCalledWith(7, "J'ai une bombarde"));
    expect(await within(carte).findByText('reply_sent')).toBeInTheDocument();
    expect(within(carte).queryByRole('button', {name: 'edit'})).not.toBeInTheDocument();
  });

  it('shouldLetTheOwnerEditAndDeleteTheirOwnAd', async () => {
    connecte('anna');
    (updateAnnonce as jest.Mock).mockResolvedValue({...annonces[0], titre: 'Vends bombarde en si bémol', typeId: 2});
    (deleteAnnonce as jest.Mock).mockResolvedValue(undefined);
    render(<AnnoncesBoard locale="fr" />);
    const carte = (await screen.findByText('Vends bombarde')).closest('article') as HTMLElement;
    expect(within(carte).queryByRole('button', {name: 'reply'})).not.toBeInTheDocument();

    fireEvent.click(within(carte).getByRole('button', {name: 'edit'}));
    fireEvent.change(within(carte).getByLabelText('titre'), {target: {value: 'Vends bombarde en si bémol'}});
    fireEvent.change(within(carte).getByLabelText('type'), {target: {value: '2'}});
    fireEvent.click(within(carte).getByRole('button', {name: 'save'}));

    await waitFor(() => expect(updateAnnonce).toHaveBeenCalledWith(7, {titre: 'Vends bombarde en si bémol', texte: 'Très bon état', typeId: 2}));
    expect(await screen.findByText('Vends bombarde en si bémol')).toBeInTheDocument();

    const carteMaj = screen.getByText('Vends bombarde en si bémol').closest('article') as HTMLElement;
    fireEvent.click(within(carteMaj).getByRole('button', {name: 'delete'}));

    await waitFor(() => expect(deleteAnnonce).toHaveBeenCalledWith(7));
    await waitFor(() => expect(screen.queryByText('Vends bombarde en si bémol')).not.toBeInTheDocument());
  });

  it('shouldLetAMemberPostANewAd', async () => {
    connecte('soazig');
    (createAnnonce as jest.Mock).mockResolvedValue({id: 9, titre: 'Donne cours de harpe', texte: 'Le mardi', date: '2026-09-18', typeId: 2, auteur: {id: 9, pseudo: 'soazig'}});
    render(<AnnoncesBoard locale="fr" />);
    await screen.findByText('Vends bombarde');

    fireEvent.click(screen.getByRole('button', {name: 'create'}));
    const formulaire = screen.getByTestId('annonce-form');
    fireEvent.change(within(formulaire).getByLabelText('titre'), {target: {value: 'Donne cours de harpe'}});
    fireEvent.change(within(formulaire).getByLabelText('texte'), {target: {value: 'Le mardi'}});
    fireEvent.change(within(formulaire).getByLabelText('type'), {target: {value: '2'}});
    fireEvent.click(within(formulaire).getByRole('button', {name: 'submit'}));

    await waitFor(() => expect(createAnnonce).toHaveBeenCalledWith({titre: 'Donne cours de harpe', texte: 'Le mardi', typeId: 2}));
    expect(await screen.findByText('Donne cours de harpe')).toBeInTheDocument();
  });

  it('shouldSayWhenThereIsNoAd', async () => {
    (getAnnonces as jest.Mock).mockResolvedValue([]);
    render(<AnnoncesBoard locale="fr" />);

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