import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Navigate, Route, Routes } from 'react-router-dom';
import { ToastProvider } from './toast';
import { I18nProvider } from './i18n/I18nProvider';
import CorrespondenceInboxPage from './views/CorrespondenceInboxPage';
import { api } from './api';

jest.mock('./api', () => ({
  api: {
    get: jest.fn(),
    post: jest.fn(),
    put: jest.fn(),
    patch: jest.fn(),
    delete: jest.fn(),
    interceptors: { request: { use: jest.fn() }, response: { use: jest.fn() } },
  },
  getApiErrorMessage: (error: any, fallback?: string) => fallback || 'Request failed.',
}));

const mockedApi = api as jest.Mocked<typeof api>;

function renderPage() {
  return render(
    <ToastProvider>
      <I18nProvider>
        <MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
          <CorrespondenceInboxPage />
        </MemoryRouter>
      </I18nProvider>
    </ToastProvider>,
  );
}

describe('CorrespondenceInboxPage', () => {
  beforeEach(() => {
    mockedApi.get.mockImplementation((url: string) => {
      if (url === '/email/providers') return Promise.resolve({ data: [
        { provider: 'gmail', displayName: 'Gmail', connected: true, address: 'owner@gmail.test', canRead: true, canSend: false },
        { provider: 'microsoft', displayName: 'Outlook', connected: false, address: null, canRead: false, canSend: false },
      ] } as any);
      if (url === '/correspondence') return Promise.resolve({ data: [
        {
          id: 1,
          jobApplicationId: 42,
          companyName: 'Acme Systems',
          jobTitle: 'Backend Engineer',
          from: 'Company',
          direction: 'inbound',
          subject: 'Interview invite',
          channel: 'Email',
          date: new Date().toISOString(),
          contentPreview: 'We would like to schedule an interview.',
          externalThreadId: 'thread-1',
          externalMessageId: 'message-1',
          provider: 'gmail',
          externalFrom: 'Maria Recruiter <maria@acme.test>',
          externalTo: 'user@example.test',
          labelCount: 2,
          attachmentCount: 1,
        },
      ] } as any);
      if (url === '/email/message') return Promise.resolve({ data: {
        id: 'message-1', threadId: 'thread-1', subject: 'Interview invite', from: 'Maria Recruiter <maria@acme.test>', to: 'user@example.test',
        date: new Date().toISOString(), snippet: 'Interview', bodyText: 'Please choose an interview time.', labels: ['INBOX'], attachments: [{ fileName: 'agenda.pdf' }],
      } } as any);
      if (url === '/gmail/review-candidates') return Promise.resolve({ data: {
        queries: [], candidateThreadCount: 0, autoLinkThreadCount: 0, reviewThreadCount: 0, unmatchedThreadCount: 0, threads: [],
      } } as any);
      if (url === '/gmail/suggested-jobs') return Promise.resolve({ data: { count: 0, items: [] } } as any);
      return Promise.resolve({ data: {} } as any);
    });
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  test('renders correspondence inbox items and reloads with filters', async () => {
    renderPage();

    expect(await screen.findByRole('heading', { name: /job email/i })).toBeInTheDocument();
    expect(await screen.findByText(/1 items/i)).toBeInTheDocument();
    expect(await screen.findByText(/acme systems/i)).toBeInTheDocument();
    expect(await screen.findByText(/backend engineer/i)).toBeInTheDocument();
    expect(screen.getByText(/2 labels/i)).toBeInTheDocument();
    expect(screen.getByText(/1 attachments/i)).toBeInTheDocument();
    expect(screen.getByText(/Gmail: owner@gmail\.test · Read only/i)).toBeInTheDocument();
    expect(screen.getByText(/Outlook: Not connected · Read only/i)).toBeInTheDocument();

    fireEvent.change(screen.getByLabelText(/search/i), { target: { value: 'Maria' } });
    fireEvent.mouseDown(screen.getAllByRole('combobox')[0]);
    fireEvent.click((await screen.findAllByRole('option', { name: /Inbound/i }))[0]);

    await waitFor(() => {
      expect(mockedApi.get).toHaveBeenLastCalledWith('/correspondence', expect.objectContaining({
        params: expect.objectContaining({
          q: 'Maria',
          direction: 'inbound',
        }),
      }));
    });
  });

  test('opens provider-backed plain-text message detail in the hub', async () => {
    renderPage();

    fireEvent.click(await screen.findByRole('button', { name: /view message/i }));

    expect(await screen.findByText(/please choose an interview time/i)).toBeInTheDocument();
    expect(screen.getByText('INBOX')).toBeInTheDocument();
    expect(screen.getByText('agenda.pdf')).toBeInTheDocument();
    expect(mockedApi.get).toHaveBeenCalledWith('/email/message', {
      params: { provider: 'gmail', messageId: 'message-1' },
    });
  });

  test('falls back to the saved copy when provider detail is unavailable', async () => {
    const original = mockedApi.get.getMockImplementation();
    mockedApi.get.mockImplementation((url: string, config?: any) => {
      if (url === '/email/message') return Promise.reject(new Error('reauthorization required'));
      if (url === '/correspondence/message/1') return Promise.resolve({ data: {
        id: 'message-1', threadId: 'thread-1', subject: 'Interview invite', from: 'Maria Recruiter', to: 'user@example.test',
        date: new Date().toISOString(), snippet: 'Saved', bodyText: 'Saved interview message.', labels: [], attachments: [],
      } } as any);
      return original!(url, config);
    });

    renderPage();
    fireEvent.click(await screen.findByRole('button', { name: /view message/i }));

    expect(await screen.findByText(/showing the saved jobtracker copy/i)).toBeInTheDocument();
    expect(await screen.findByText(/saved interview message/i)).toBeInTheDocument();
    expect(mockedApi.get).toHaveBeenCalledWith('/correspondence/message/1');
  });

  test('uses one hub for linked messages and recruitment suggestions', async () => {
    renderPage();

    fireEvent.click(await screen.findByRole('button', { name: /review suggestions/i }));
    expect(await screen.findByRole('heading', { name: /recruitment message review/i })).toBeInTheDocument();
    expect(mockedApi.get).toHaveBeenCalledWith('/gmail/review-candidates');
    expect(screen.getByRole('button', { name: /linked messages/i })).toBeInTheDocument();
  });

  test('legacy Gmail review route redirects into the consolidated hub filter', async () => {
    render(
      <ToastProvider>
        <I18nProvider>
          <MemoryRouter initialEntries={['/correspondence/review']} future={{ v7_startTransition: true, v7_relativeSplatPath: true }}>
            <Routes>
              <Route path="/correspondence/review" element={<Navigate to="/correspondence?view=review" replace />} />
              <Route path="/correspondence" element={<CorrespondenceInboxPage />} />
            </Routes>
          </MemoryRouter>
        </I18nProvider>
      </ToastProvider>,
    );

    expect(await screen.findByRole('heading', { name: /recruitment message review/i })).toBeInTheDocument();
    expect(mockedApi.get).not.toHaveBeenCalledWith('/correspondence', expect.anything());
  });
});
