import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import { ProtectedRoute } from '@/components/ProtectedRoute';
import { ToastProvider } from '@/hooks/useToast';
import { AuthProvider } from '@/hooks/useAuth';
import { setToken } from '@/api/client';
import { ToastViewport } from '@/components/Toast';

// Mock the auth API so AuthProvider hydrates without network.
vi.mock('@/api/auth', () => ({
  login: vi.fn(),
  logout: vi.fn(),
  fetchMe: vi.fn(),
}));

import { fetchMe } from '@/api/auth';

function setup() {
  return render(
    <MemoryRouter initialEntries={['/admin']}>
      <ToastProvider>
        <AuthProvider>
          <Routes>
            <Route path="/login" element={<div>LOGIN PAGE</div>} />
            <Route path="/engagements" element={<div>ENGAGEMENTS</div>} />
            <Route element={<ProtectedRoute roles={['admin']} />}>
              <Route path="/admin" element={<div>ADMIN AREA</div>} />
            </Route>
          </Routes>
          <ToastViewport />
        </AuthProvider>
      </ToastProvider>
    </MemoryRouter>,
  );
}

describe('ProtectedRoute', () => {
  beforeEach(() => {
    localStorage.clear();
    vi.mocked(fetchMe).mockReset();
  });

  afterEach(() => {
    setToken(null);
  });

  it('redirects unauthenticated users to /login', async () => {
    // No token → unauthenticated, no /me call.
    setup();
    expect(await screen.findByText('LOGIN PAGE')).toBeInTheDocument();
  });

  it('admins reach the admin page', async () => {
    setToken('fake-token');
    vi.mocked(fetchMe).mockResolvedValue({
      id: 1,
      username: 'alice',
      role: 'admin',
      created_at: '2026-01-01',
    });
    setup();
    expect(await screen.findByText('ADMIN AREA')).toBeInTheDocument();
  });

  it('non-admins get redirected and see an access denied toast', async () => {
    setToken('fake-token');
    vi.mocked(fetchMe).mockResolvedValue({
      id: 2,
      username: 'bob',
      role: 'soc',
      created_at: '2026-01-01',
    });
    setup();
    expect(await screen.findByText('ENGAGEMENTS')).toBeInTheDocument();
    await waitFor(() => {
      expect(screen.getByTestId('toast')).toHaveTextContent('Accès refusé');
    });
  });
});
