import React from 'react';
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import CarpoolSection from '../CarpoolSection';
import { getCarpoolsByEvenement, updateCarpool, Carpool } from '@/services/covoiturageService';

const mockUseAuth = jest.fn();

jest.mock('@/services/covoiturageService');
jest.mock('@/contexts/AuthContext', () => ({
  useAuth: () => mockUseAuth(),
}));
jest.mock('next/link', () => {
  return ({ children, href, ...props }: { children: React.ReactNode; href: string; [key: string]: unknown }) => (
    <a href={href} {...props}>{children}</a>
  );
});

const mockedGetCarpools = getCarpoolsByEvenement as jest.MockedFunction<typeof getCarpoolsByEvenement>;

const carpoolByBreizh56: Carpool = {
  id: 7,
  ville: 'Rennes',
  nombre: 3,
  heure: '18:00',
  propose: 1,
  auteur: { id: 42, pseudo: 'breizh56' },
};

function signedInAs(username: string | null) {
  mockUseAuth.mockReturnValue({
    isAuthenticated: username !== null,
    user: username === null ? null : { id: '1', username },
  });
}

describe('CarpoolSection', () => {
  beforeEach(() => {
    jest.clearAllMocks();
    mockedGetCarpools.mockResolvedValue([carpoolByBreizh56]);
  });

  it('shouldOfferContactToAnAuthenticatedUserWhoIsNotTheAuthor', async () => {
    signedInAs('yann22');

    render(<CarpoolSection evenementId={10} />);

    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    expect(screen.getByRole('button', { name: 'contact' })).toBeInTheDocument();
  });

  it('shouldOfferDeleteInsteadOfContactToTheAuthor', async () => {
    signedInAs('breizh56');

    render(<CarpoolSection evenementId={10} />);

    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    expect(screen.getByRole('button', { name: 'delete' })).toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'contact' })).not.toBeInTheDocument();
  });

  it('shouldShowALoginLinkAndNoContactButtonToAnonymousVisitors', async () => {
    signedInAs(null);

    render(<CarpoolSection evenementId={10} />);

    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    expect(screen.getByText('login_to_carpool').closest('a')).toHaveAttribute('href', '/connexion');
    expect(screen.queryByRole('button', { name: 'contact' })).not.toBeInTheDocument();
    expect(screen.queryByRole('button', { name: 'delete' })).not.toBeInTheDocument();
  });

  it('shouldNeverRenderAnEmailAddressEvenIfTheApiLeaksOne', async () => {
    signedInAs('yann22');
    // Defensive: even if the payload ever carried an e-mail, it must not reach the DOM.
    mockedGetCarpools.mockResolvedValue([
      {
        ...carpoolByBreizh56,
        auteur: { id: 42, pseudo: 'breizh56', email: 'breizh56@example.com' },
      } as unknown as Carpool,
    ]);

    render(<CarpoolSection evenementId={10} />);

    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    expect(document.body.textContent).not.toMatch(/[\w.+-]+@[\w-]+\.[\w.]+/);
    expect(document.body.innerHTML).not.toContain('mailto:');
    expect(document.body.innerHTML).not.toContain('example.com');
  });

  it('shouldLetTheAuthorEditTheirCarpool', async () => {
    signedInAs('breizh56');
    (updateCarpool as jest.Mock).mockResolvedValue({ ...carpoolByBreizh56, ville: 'Brest', nombre: 2 });
    render(<CarpoolSection evenementId={10} />);
    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    fireEvent.click(screen.getByRole('button', { name: 'edit' }));
    const ville = screen.getByLabelText('city') as HTMLInputElement;
    expect(ville.value).toBe('Rennes');
    fireEvent.change(ville, { target: { value: 'Brest' } });
    fireEvent.change(screen.getByLabelText('seats'), { target: { value: '2' } });
    fireEvent.click(screen.getByRole('button', { name: 'save' }));

    await waitFor(() => {
      expect(updateCarpool).toHaveBeenCalledWith(7, { ville: 'Brest', nombre: 2, heure: '18:00', propose: 1 });
    });
    expect(screen.getByText(/Brest — 2 seats_label/)).toBeInTheDocument();
  });

  it('shouldNotOfferEditToOtherUsers', async () => {
    signedInAs('yann22');
    render(<CarpoolSection evenementId={10} />);
    await waitFor(() => {
      expect(screen.getByText('breizh56')).toBeInTheDocument();
    });

    expect(screen.queryByRole('button', { name: 'edit' })).not.toBeInTheDocument();
  });
});
