import React from 'react';
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { ToastProvider } from './toast';
import { I18nProvider } from './i18n/I18nProvider';
import ProfilePage from './pages/ProfilePage';
import { api } from './api';

const createObjectURLMock = jest.fn(() => 'blob:mock-pdf');
const revokeObjectURLMock = jest.fn();
Object.defineProperty(window.URL, 'createObjectURL', {
  writable: true,
  value: createObjectURLMock,
});
Object.defineProperty(window.URL, 'revokeObjectURL', {
  writable: true,
  value: revokeObjectURLMock,
});

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() } },
  },
}));

jest.mock('./components/GoogleAuthCard', () => () => null);
jest.mock('./components/CropImageDialog', () => () => null);

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

const REWRITE_TEMPLATES_COUNT = 6;

const structuredCv = {
  version: '1',
  metadata: {
    profileVersion: 3,
    appliedExtractionRunId: 12,
    updatedAtUtc: '2026-03-28T12:00:00Z',
    fields: {
      'contact.fullName': { confidence: 0.92, method: 'llm', sourceBlockId: 'block-1', reviewState: 'suggested', sourceSnippet: 'Demo User' },
      summary: { confidence: 0.71, method: 'deterministic', sourceBlockId: 'block-2', reviewState: 'suggested', sourceSnippet: 'Built backend systems' },
      skills: { confidence: 0.68, method: 'deterministic', sourceBlockId: 'block-3', reviewState: 'suggested', sourceSnippet: '.NET' },
    },
  },
  contact: {
    fullName: 'Demo User',
    headline: 'Backend Developer',
    email: 'demo@example.com',
  },
  summary: ['Built backend systems'],
  jobs: [
    {
      title: 'System Developer',
      company: 'Demo Co',
      location: 'Oslo',
      start: '2020',
      end: '2024',
      isCurrent: false,
      bullets: ['Built backend systems'],
      skills: ['.NET', 'SQL'],
    },
  ],
  education: [],
  skills: ['.NET', 'SQL'],
  languages: [{ name: 'English', level: 'Native' }],
  interests: ['Cooking'],
  otherSections: [],
  sections: [
    { name: 'Professional Summary', content: 'Built backend systems', wordCount: 3 },
    { name: 'Skills', content: '.NET\nSQL', wordCount: 2 },
  ],
};

function renderPage() {
  return render(
    <ToastProvider>
      <I18nProvider>
        <ProfilePage />
      </I18nProvider>
    </ToastProvider>,
  );
}

beforeEach(() => {
  mockedApi.get.mockImplementation((url: string) => {
    if (url === '/auth/me') {
      return Promise.resolve({
        data: {
          provider: 'local',
          email: 'demo@example.com',
          userName: 'demo',
          firstName: 'Demo',
          lastName: 'User',
          displayName: 'Demo User',
          profileCvText: 'Professional Summary\nBuilt backend systems',
          profileCvStructureJson: JSON.stringify(structuredCv),
          googleLink: { linked: false },
        },
      } as any);
    }
    if (url === '/profile-cv/runs') {
      return Promise.resolve({
        data: [
          {
            id: 12,
            trigger: 'upload',
            status: 'applied',
            artifactFileName: 'resume.pdf',
            startedAtUtc: '2026-03-28T12:00:00Z',
            completedAtUtc: '2026-03-28T12:00:05Z',
            appliedAtUtc: '2026-03-28T12:00:05Z',
            parserVersion: 'm005-s01',
            normalizerVersion: 'm005-s01',
            llmPromptVersion: 'm005-s01',
          },
        ],
      } as any);
    }
    if (url === '/jobapplications') {
      return Promise.resolve({
        data: {
          items: [
            {
              id: 42,
              jobTitle: 'Senior Backend Engineer',
              company: { id: 7, name: 'Acme Systems' },
              status: 'Waiting',
              dateApplied: '2026-03-20',
              daysSince: 10,
              description: 'Build API integrations and platform workflows.',
              responseReceived: false,
            },
          ],
          total: 1,
          page: 1,
          pageSize: 100,
        },
      } as any);
    }
    return Promise.resolve({ data: {} } as any);
  });
  mockedApi.post.mockImplementation((url: string, payload?: any, config?: any) => {
    if (url === '/profile-cv/parse') {
      return Promise.resolve({
        data: {
          structuredCv: {
            ...structuredCv,
            sections: [
              { name: 'Professional Summary', content: 'Built backend systems', wordCount: 3 },
              { name: 'Core Skills', content: '.NET\nSQL\nAzure', wordCount: 3 },
            ],
            skills: ['.NET', 'SQL', 'Azure'],
          },
        },
      } as any);
    }
    if (url === '/profile-cv/rewrite-preview') {
      return Promise.resolve({ data: { templateId: 'harvard', html: '<html><body>Preview</body></html>', suggestedFileName: 'harvard-preview.pdf', fullText: 'Professional Summary\nClearer, sharper positioning for backend platform roles.', rewrittenText: 'Professional Summary\nClearer, sharper positioning for backend platform roles.', structuredCv, sectionName: null, jobApplicationId: 42, targetRole: 'Senior Backend Engineer' } } as any);
    }
    if (url === '/profile-cv/export-pdf') {
      return Promise.resolve({ data: new Blob([`pdf-${payload?.templateId ?? 'ats-minimal'}`], { type: 'application/pdf' }), config } as any);
    }
    if (url === '/profile-cv/reprocess') {
      return Promise.resolve({ data: { reprocessed: true } } as any);
    }
    return Promise.resolve({ data: {} } as any);
  });
  mockedApi.put.mockResolvedValue({ data: {} } as any);
  window.localStorage.clear();
});

afterEach(() => {
  jest.clearAllMocks();
  createObjectURLMock.mockClear();
  revokeObjectURLMock.mockClear();
});

test('profile page loads persisted structured cv and can re-parse it', async () => {
  renderPage();

  expect(await screen.findByText(/cv ready/i)).toBeInTheDocument();
  expect(screen.getByText(/cv structure overview/i)).toBeInTheDocument();
  expect(screen.getByText(/structured cv editor/i)).toBeInTheDocument();
  expect(screen.getByText(/extraction history/i)).toBeInTheDocument();
  expect(screen.getByText(/resume.pdf/i)).toBeInTheDocument();
  expect(screen.getByText(/current run/i)).toBeInTheDocument();
  expect(screen.getAllByText(/original extraction/i).length).toBeGreaterThan(0);
  const originalExtractionToggle = screen.getByRole('button', { name: /original extraction/i });
  expect(originalExtractionToggle).toHaveAttribute('aria-expanded', 'false');
  expect(screen.getAllByText(/professional summary/i).length).toBeGreaterThan(0);
  expect(screen.getByLabelText(/full name/i)).toHaveValue('Demo User');
  expect(screen.getByText(/high 92%/i)).toBeInTheDocument();
  expect(screen.getByText(/block-1/i)).toBeInTheDocument();

  fireEvent.click(originalExtractionToggle);
  expect(originalExtractionToggle).toHaveAttribute('aria-expanded', 'true');
  expect(await screen.findByLabelText(/profile cv \/ master resume text/i)).toHaveValue('Professional Summary\nBuilt backend systems');

  const analyzeButton = screen.getByRole('button', { name: /analyze sections/i });
  await waitFor(() => expect(analyzeButton).toBeEnabled());
  fireEvent.click(analyzeButton);

  await waitFor(() => {
    expect(mockedApi.post).toHaveBeenCalledWith('/profile-cv/parse', { text: 'Professional Summary\nBuilt backend systems' });
  });

  expect(screen.getAllByText(/core skills/i).length).toBeGreaterThan(0);
});

test('profile page can reprocess from stored artifact history', async () => {
  renderPage();

  expect(await screen.findByText(/extraction history/i)).toBeInTheDocument();
  const reprocessButton = screen.getByRole('button', { name: /reprocess cv/i });
  fireEvent.click(reprocessButton);

  await waitFor(() => {
    expect(mockedApi.post).toHaveBeenCalledWith('/profile-cv/reprocess');
  });
});

test('profile page keeps raw extraction collapsed until expanded', async () => {
  renderPage();

  expect(await screen.findByText(/cv ready/i)).toBeInTheDocument();
  expect(screen.getByText(/the structured cv stays front and center/i)).toBeInTheDocument();

  const originalExtractionToggle = screen.getByRole('button', { name: /original extraction/i });
  expect(originalExtractionToggle).toHaveAttribute('aria-expanded', 'false');
  const copyButton = screen.getByRole('button', { name: /copy cv text/i });
  expect(copyButton).toBeDisabled();

  fireEvent.click(originalExtractionToggle);

  expect(originalExtractionToggle).toHaveAttribute('aria-expanded', 'true');
  expect(await screen.findByLabelText(/profile cv \/ master resume text/i)).toHaveValue('Professional Summary\nBuilt backend systems');
  const copyButtons = screen.getAllByRole('button', { name: /copy cv text/i });
  expect(copyButtons.some((button) => !button.hasAttribute('disabled'))).toBe(true);
});

test('profile page rewrite tools use selected template and saved job context', async () => {
  renderPage();

  expect(await screen.findByText(/template-driven cv builder/i)).toBeInTheDocument();
  fireEvent.click(screen.getByText(/harvard/i));
  fireEvent.mouseDown(screen.getAllByRole('combobox')[1]);
  fireEvent.click(await screen.findByText(/senior backend engineer · acme systems/i));

  const rewriteButton = screen.getByRole('button', { name: /build preview/i });
  fireEvent.click(rewriteButton);

  await waitFor(() => {
    expect(mockedApi.post).toHaveBeenCalledWith('/profile-cv/rewrite-preview', expect.objectContaining({
      sectionName: null,
      style: 'harvard',
      templateId: 'harvard',
      jobApplicationId: 42,
    }));
  });

  expect(await screen.findByText(/preview ready/i)).toBeInTheDocument();
  expect(screen.getByText(/clearer, sharper positioning for backend platform roles/i)).toBeInTheDocument();
  expect(screen.getByRole('heading', { name: /pdf carousel/i })).toBeInTheDocument();

  const buildCarouselButton = screen.getByRole('button', { name: /build pdf carousel/i });
  fireEvent.click(buildCarouselButton);

  await waitFor(() => {
    const exportCalls = mockedApi.post.mock.calls.filter(([url]) => url === '/profile-cv/export-pdf');
    expect(exportCalls.length).toBe(REWRITE_TEMPLATES_COUNT);
  });

  await waitFor(() => expect(createObjectURLMock).toHaveBeenCalledTimes(REWRITE_TEMPLATES_COUNT));
});

test('saving profile persists structured cv json', async () => {
  renderPage();

  expect(await screen.findByText(/cv ready/i)).toBeInTheDocument();
  const fullNameInput = screen.getByLabelText(/full name/i);
  fireEvent.change(fullNameInput, { target: { value: 'Updated Demo User' } });

  const saveButton = screen.getByRole('button', { name: /save changes/i });
  await waitFor(() => expect(saveButton).toBeEnabled());
  fireEvent.click(saveButton);

  await waitFor(() => {
    expect(mockedApi.put).toHaveBeenCalled();
  });

  const payload = mockedApi.put.mock.calls[0][1] as any;
  const parsed = JSON.parse(payload.profileCvStructureJson);
  expect(parsed.contact.fullName).toBe('Updated Demo User');
  expect(parsed.skills).toEqual(['.NET', 'SQL']);
  expect(parsed.jobs[0].title).toBe('System Developer');
});
