import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { MemoryRouter, Route, Routes, useLocation } from 'react-router-dom';
import { ConfirmProvider } from './confirm';
import { PromptProvider } from './prompt';
import { ToastProvider } from './toast';
import { I18nProvider } from './i18n/I18nProvider';
import DashboardView from './components/DashboardView';
import RemindersView from './components/RemindersView';
import JobTable from './components/JobTable';
import { api } from './api';
import { JobApplication } from './types';

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

function buildJob(overrides: Partial<JobApplication>): JobApplication {
  return {
    id: 1,
    jobTitle: 'Backend Developer',
    company: { id: 1, name: 'Acme' },
    companyId: 1,
    status: 'Waiting',
    dateApplied: new Date('2026-03-01T00:00:00Z').toISOString(),
    savedAt: new Date('2026-03-01T00:00:00Z').toISOString(),
    location: 'Oslo',
    salary: undefined,
    nextAction: undefined,
    followUpAt: new Date('2026-03-20T00:00:00Z').toISOString(),
    feedbackRequestedAt: undefined,
    responseReceived: false,
    responseDate: undefined,
    description: 'Role summary',
    translatedDescription: undefined,
    descriptionLanguage: undefined,
    tags: undefined,
    deadline: undefined,
    notes: 'General notes',
    coverLetterText: undefined,
    recruiterMessageDraft: undefined,
    jobUrl: undefined,
    shortSummary: 'Strong match',
    fullSummary: null,
    tailoredCvText: 'Saved CV',
    tailoredCvUpdatedAt: null,
    workflowSignal: {
      actionKey: 'follow-up',
      reason: 'Follow-up is due for this role.',
      workspaceTab: 'follow-up',
      followMode: 'waiting-update',
      needsAttention: true,
      hasPackageGap: false,
      needsInterviewPrep: false,
      needsFollowUpAction: true,
      hasTailoredCv: true,
      hasSavedApplicationAnswerDraft: true,
      hasInterviewPrepNotes: true,
    },
    hasResume: true,
    hasCoverLetter: false,
    hasPortfolio: false,
    hasOtherAttachment: false,
    daysSince: 10,
    isDeleted: false,
    deletedAt: undefined,
    needsFollowUp: true,
    followUpReason: 'Follow-up is due for this role.',
    ...overrides,
  };
}

function setupApiMocks({ reminders, jobs }: { reminders?: JobApplication[]; jobs?: JobApplication[] }) {
  mockedApi.get.mockImplementation((url: string, config?: any) => {
    if (url === '/companies') return Promise.resolve({ data: [{ id: 1, name: 'Acme' }, { id: 2, name: 'Beta' }] } as any);
    if (url === '/jobapplications/reminders') return Promise.resolve({ data: reminders ?? [] } as any);
    if (url === '/jobapplications') {
      const readiness = config?.params?.readiness;
      const filtered = (jobs ?? []).filter((job) => readiness === 'interview'
        ? job.workflowSignal?.needsInterviewPrep
        : readiness === 'needs-work'
          ? job.workflowSignal?.hasPackageGap || job.workflowSignal?.needsInterviewPrep
          : true);
      return Promise.resolve({ data: { items: filtered, total: filtered.length, page: 1, pageSize: 15 } } as any);
    }
    if (url === '/jobapplications/stats') return Promise.resolve({ data: { total: reminders?.length ?? 0, active: reminders?.length ?? 0, deleted: 0, byStatus: {}, appliedLast30Days: reminders?.length ?? 0, averageDaysSinceApplied: 7 } } as any);
    if (url === '/jobapplications/analytics-overview') return Promise.resolve({ data: { funnel: [], responseRateBySource: [], topCompanies: [], totalResponses: 1, totalActive: reminders?.length ?? 0 } } as any);
    if (url === '/jobapplications/analytics' || url === '/jobapplications/tags') return Promise.resolve({ data: [] } as any);
    if (url === '/jobapplications/tag-trends') return Promise.resolve({ data: { months: [], series: [] } } as any);
    return Promise.resolve({ data: [] } as any);
  });
}

function LocationIndicator() {
  const location = useLocation();
  return <div data-testid="location-indicator">{location.pathname}{location.search}</div>;
}

function renderWithProviders(initialPath: string, routes: React.ReactNode) {
  return render(
    <ToastProvider>
      <I18nProvider>
        <ConfirmProvider>
          <PromptProvider>
            <MemoryRouter initialEntries={[initialPath]}>
              <Routes>{routes}</Routes>
            </MemoryRouter>
          </PromptProvider>
        </ConfirmProvider>
      </I18nProvider>
    </ToastProvider>,
  );
}

beforeEach(() => {
  window.localStorage.clear();
});

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

test('follow-up workflow signals route all overview surfaces to the same follow-up workspace', async () => {
  const job = buildJob({
    id: 42,
    followUpReason: 'Tailored CV missing',
    workflowSignal: {
      actionKey: 'follow-up',
      reason: 'Follow-up is due for this role.',
      workspaceTab: 'follow-up',
      followMode: 'waiting-update',
      needsAttention: true,
      hasPackageGap: false,
      needsInterviewPrep: false,
      needsFollowUpAction: true,
      hasTailoredCv: true,
      hasSavedApplicationAnswerDraft: true,
      hasInterviewPrepNotes: true,
    },
  });

  setupApiMocks({ reminders: [job], jobs: [job] });

  const dashboardRender = renderWithProviders('/dashboard', <>
    <Route path="/dashboard" element={<><LocationIndicator /><DashboardView /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  await screen.findByText(/follow-up is due for this role/i);
  fireEvent.click(await screen.findByRole('button', { name: /follow up/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
  dashboardRender.unmount();

  setupApiMocks({ reminders: [job], jobs: [job] });
  const remindersRender = renderWithProviders('/reminders', <>
    <Route path="/reminders" element={<><LocationIndicator /><RemindersView /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  fireEvent.click(await screen.findByRole('button', { name: /follow up/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
  remindersRender.unmount();

  setupApiMocks({ reminders: [job], jobs: [job] });
  renderWithProviders('/table', <>
    <Route path="/table" element={<><LocationIndicator /><JobTable refreshToken={0} pageSize={15} onPageSizeChange={() => {}} columns={{ status: true, dateApplied: true, daysSince: true, jobUrl: false }} onColumnsChange={() => {}} mode="jobs" /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  fireEvent.click(await screen.findByRole('button', { name: /backend developer — follow up signal/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/42?section=communication&followMode=waiting-update'));
});

test('package-work workflow signals route all overview surfaces to the shared tailored-cv workspace', async () => {
  const job = buildJob({
    id: 43,
    jobTitle: 'Platform Engineer',
    followUpReason: 'Follow-up due soon',
    workflowSignal: {
      actionKey: 'package-work',
      reason: 'Saved application answers still need work.',
      workspaceTab: 'tailored-cv',
      followMode: null,
      needsAttention: true,
      hasPackageGap: true,
      needsInterviewPrep: false,
      needsFollowUpAction: true,
      hasTailoredCv: true,
      hasSavedApplicationAnswerDraft: false,
      hasInterviewPrepNotes: true,
    },
  });

  setupApiMocks({ reminders: [job], jobs: [job] });

  const dashboardRender = renderWithProviders('/dashboard', <>
    <Route path="/dashboard" element={<><LocationIndicator /><DashboardView /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  fireEvent.click(await screen.findByRole('button', { name: /build package/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
  dashboardRender.unmount();

  setupApiMocks({ reminders: [job], jobs: [job] });
  const remindersRender = renderWithProviders('/reminders', <>
    <Route path="/reminders" element={<><LocationIndicator /><RemindersView /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  fireEvent.click(await screen.findByRole('button', { name: /build package/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
  remindersRender.unmount();

  setupApiMocks({ reminders: [job], jobs: [job] });
  renderWithProviders('/table', <>
    <Route path="/table" element={<><LocationIndicator /><JobTable refreshToken={0} pageSize={15} onPageSizeChange={() => {}} columns={{ status: true, dateApplied: true, daysSince: true, jobUrl: false }} onColumnsChange={() => {}} mode="jobs" /></>} />
    <Route path="/jobs/:id" element={<LocationIndicator />} />
  </>);

  fireEvent.click(await screen.findByRole('button', { name: /platform engineer — build package signal/i }));
  await waitFor(() => expect(screen.getByTestId('location-indicator')).toHaveTextContent('/jobs/43?section=cv'));
});

test('job table readiness filter follows workflow signals instead of raw notes or cv text heuristics', async () => {
  const packageGapJob = buildJob({
    id: 44,
    jobTitle: 'Application Engineer',
    status: 'Applied',
    notes: 'General notes only',
    tailoredCvText: 'Saved tailored CV',
    workflowSignal: {
      actionKey: 'package-work',
      reason: 'Saved application answers still need work.',
      workspaceTab: 'tailored-cv',
      followMode: null,
      needsAttention: true,
      hasPackageGap: true,
      needsInterviewPrep: false,
      needsFollowUpAction: false,
      hasTailoredCv: true,
      hasSavedApplicationAnswerDraft: false,
      hasInterviewPrepNotes: true,
    },
  });

  const readyRejectedJob = buildJob({
    id: 45,
    jobTitle: 'Operations Analyst',
    status: 'Rejected',
    notes: 'Some notes',
    tailoredCvText: null,
    needsFollowUp: false,
    followUpReason: null,
    workflowSignal: {
      actionKey: 'review-readiness',
      reason: 'No urgent workflow gaps are blocking this job right now.',
      workspaceTab: 'readiness',
      followMode: null,
      needsAttention: false,
      hasPackageGap: false,
      needsInterviewPrep: false,
      needsFollowUpAction: false,
      hasTailoredCv: false,
      hasSavedApplicationAnswerDraft: false,
      hasInterviewPrepNotes: false,
    },
  });

  setupApiMocks({ jobs: [packageGapJob, readyRejectedJob] });

  renderWithProviders('/table', <>
    <Route path="/table" element={<JobTable refreshToken={0} pageSize={15} onPageSizeChange={() => {}} columns={{ status: true, dateApplied: true, daysSince: true, jobUrl: false }} onColumnsChange={() => {}} mode="jobs" />} />
  </>);

  const readinessSelect = (await screen.findAllByRole('combobox')).find((element) => /all readiness/i.test(element.textContent ?? ''));
  expect(readinessSelect).toBeTruthy();
  fireEvent.mouseDown(readinessSelect as HTMLElement);
  fireEvent.click(await screen.findByRole('option', { name: /needs work/i }));

  expect(await screen.findByText(/application engineer/i)).toBeInTheDocument();
  await waitFor(() => expect(screen.queryByText(/operations analyst/i)).not.toBeInTheDocument());
  expect(mockedApi.get).toHaveBeenCalledWith('/jobapplications', expect.objectContaining({
    params: expect.objectContaining({ readiness: 'needs-work' }),
  }));
});
