import { expect, test, type Page } from "@playwright/test";

const apiUrl = "http://localhost:5302/api";

type Rgba = { red: number; green: number; blue: number; alpha: number };

function parseCssColour(value: string): Rgba {
  const parts = value.match(/[\d.]+/g)?.map(Number) ?? [];
  expect(parts.length, `expected an rgb/rgba colour but received ${value}`).toBeGreaterThanOrEqual(3);
  return { red: parts[0], green: parts[1], blue: parts[2], alpha: parts[3] ?? 1 };
}

function composite(foreground: Rgba, background: Rgba): Rgba {
  return {
    red: foreground.red * foreground.alpha + background.red * (1 - foreground.alpha),
    green: foreground.green * foreground.alpha + background.green * (1 - foreground.alpha),
    blue: foreground.blue * foreground.alpha + background.blue * (1 - foreground.alpha),
    alpha: 1,
  };
}

function relativeLuminance(colour: Rgba) {
  const linear = [colour.red, colour.green, colour.blue].map((channel) => {
    const value = channel / 255;
    return value <= 0.04045 ? value / 12.92 : ((value + 0.055) / 1.055) ** 2.4;
  });
  return linear[0] * 0.2126 + linear[1] * 0.7152 + linear[2] * 0.0722;
}

function contrastRatio(foreground: Rgba, background: Rgba) {
  const foregroundLuminance = relativeLuminance(foreground);
  const backgroundLuminance = relativeLuminance(background);
  return (Math.max(foregroundLuminance, backgroundLuminance) + 0.05)
    / (Math.min(foregroundLuminance, backgroundLuminance) + 0.05);
}

async function loginAs(page: Page, email: string, password: string) {
  await page.goto("/login");
  await page.getByLabel("Email").fill(email);
  await page.getByLabel("Current password").fill(password);
  await page.getByRole("button", { name: "Sign in", exact: true }).click();
  await expect(page).toHaveURL(/\/dashboard$/);
  await expect(page.getByRole("heading", { name: "Dashboard", exact: true })).toBeVisible();
}

async function login(page: Page) {
  await loginAs(page, "e2e@example.test", "E2ePassword123!");
}

async function csrfHeader(page: Page) {
  const cookie = (await page.context().cookies()).find((value) => value.name === "XSRF-TOKEN");
  expect(cookie, "login should issue a CSRF cookie").toBeTruthy();
  return { "X-CSRF-TOKEN": cookie!.value };
}

test.beforeEach(async ({ page }) => {
  await page.addInitScript(() => window.localStorage.setItem("uiLanguage", "en"));
});

test("public plans stay honest, responsive and keyboard accessible", async ({ page }) => {
  for (const scheme of ["light", "dark"] as const) {
    await page.addInitScript((value) => window.localStorage.setItem("jobtracker.themeMode", value), scheme);
    await page.goto("/");
    await expect(page.getByRole("heading", { name: "Two clear plans" })).toBeVisible();
    await expect(page.locator('section[aria-labelledby^="plan-"]')).toHaveCount(2);
    await expect(page.getByRole("heading", { name: "Free", exact: true })).toBeVisible();
    await expect(page.getByRole("heading", { name: "Pro", exact: true })).toBeVisible();
    await expect(page.getByText(/Bring your own key|Unlimited AI|Billed monthly|Most popular/i)).toHaveCount(0);
    await expect(page.locator("html")).toHaveAttribute("data-color-scheme", scheme);

    for (const width of [375, 768, 1440]) {
      await page.setViewportSize({ width, height: 900 });
      const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
      expect(overflow).toBeLessThanOrEqual(1);
    }

    await page.goto("/login");
    await expect(page.getByRole("heading", { name: "Sign in", exact: true })).toBeVisible();
    for (const width of [375, 768, 1440]) {
      await page.setViewportSize({ width, height: 900 });
      const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
      expect(overflow).toBeLessThanOrEqual(1);
    }
  }

  await page.goto("/");
  const freeAction = page.getByRole("button", { name: "Create a Free account" });
  await freeAction.focus();
  await page.keyboard.press("Enter");
  await expect(page).toHaveURL(/\/register$/);

  await page.goBack();
  const proAction = page.getByRole("button", { name: "Sign in to view Pro" });
  await proAction.focus();
  await page.keyboard.press("Enter");
  await expect(page).toHaveURL(/\/login$/);
});

test("login establishes an authenticated session", async ({ page }) => {
  await login(page);
  await expect(page.getByText("e2e@example.test").first()).toBeVisible();
  await expect(page.getByTestId("admin-version-badge")).toHaveText("ve2e-verification");
  await expect(page.getByLabel("Application version e2e-verification, commit e2e1234")).toBeVisible();

  await page.getByRole("button", { name: "Notifications" }).click();
  await expect(page.getByLabel("Notifications panel")).toBeVisible();
  await expect(page).toHaveURL(/\/dashboard$/);
  await page.getByRole("button", { name: "Close" }).click();
});

test("a Free account keeps manual work available while AI actions stay honestly locked", async ({ page }) => {
  const suffix = Date.now().toString();
  const email = `free-${suffix}@example.test`;
  const password = "FreeUserPassword123!";

  await login(page);
  const headers = await csrfHeader(page);
  const createUser = await page.request.post(`${apiUrl}/users`, {
    headers,
    data: { email, password, displayName: "Free E2E User", roles: [] },
  });
  expect(createUser.ok()).toBeTruthy();

  await page.context().clearCookies();
  await loginAs(page, email, password);
  await expect(page.getByTestId("admin-version-badge")).toHaveCount(0);

  await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "dark"));
  await page.setViewportSize({ width: 375, height: 900 });
  await page.goto("/career");
  await page.getByRole("combobox", { name: "Career workspace section" }).click();
  await page.getByRole("option", { name: "Import review" }).click();
  await expect(page.getByText(/Build your Career Profile faster with Pro/)).toBeVisible();
  await page.getByRole("button", { name: "Dismiss Build your Career Profile faster with Pro." }).click();
  await expect(page.getByText(/Build your Career Profile faster with Pro/)).toHaveCount(0);
  await page.getByRole("combobox", { name: "Career workspace section" }).click();
  await page.getByRole("option", { name: "Career profile" }).click();
  await expect(page.getByLabel("Professional headline")).toBeEnabled();

  await page.goto("/settings");
  await expect(page.getByText(/Free plan includes core job tracking without AI/i)).toBeVisible();
  await expect(page.getByText(/Pro upgrades are not available in this deployment yet/i)).toBeVisible();
  await expect(page.getByRole("button", { name: "Upgrade to Pro" })).toHaveCount(0);
  const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
  expect(overflow).toBeLessThanOrEqual(1);

  await page.getByLabel("Settings section").click();
  await page.getByRole("option", { name: "Backup" }).click();
  await expect(page.getByText(/requires a sign-in from the last 15 minutes/i)).toBeVisible();
  const exportResponsePromise = page.waitForResponse((response) => response.url().endsWith("/api/export/account") && response.request().method() === "POST");
  await page.getByRole("button", { name: "Download readable account export" }).click();
  const exportResponse = await exportResponsePromise;
  expect(exportResponse.status()).toBe(200);
  expect(exportResponse.headers()["content-type"]).toContain("application/zip");
  expect((await exportResponse.body()).subarray(0, 2).toString()).toBe("PK");
  await expect(page.getByText(/Readable account export downloaded/i)).toBeVisible();
});

test("a saved job can be created through the reviewed UI flow", async ({ page }) => {
  const suffix = Date.now().toString();
  const title = `E2E Engineer ${suffix}`;

  await login(page);
  await page.goto("/jobs");
  await page.getByRole("button", { name: "Add Job" }).click();
  await page.getByRole("button", { name: "Enter details manually" }).click();
  await page.getByLabel("Company").fill(`E2E Company ${suffix}`);
  await page.getByLabel("Job title").fill(title);
  await page.getByRole("button", { name: "Continue" }).click();
  for (let step = 0; step < 3; step += 1) {
    await page.getByRole("button", { name: "Skip and continue" }).click();
  }
  await page.getByRole("button", { name: "Create job", exact: true }).click();

  await expect(page.getByText(title, { exact: true })).toBeVisible();
});

test("the dedicated application workspace survives deep links, long data and unsaved navigation", async ({ page }) => {
  const suffix = Date.now().toString();
  const companyName = `Application Workspace Company With A Deliberately Long Name ${suffix}`;
  const title = `Principal Platform Reliability Engineer For Distributed Customer Systems ${suffix}`;

  await login(page);
  const headers = await csrfHeader(page);
  let companyResponse = await page.request.post(`${apiUrl}/companies`, {
    headers,
    data: { name: companyName, location: "Oslo and remote across Europe", source: "direct" },
  });
  for (let attempt = 0; attempt < 2 && !companyResponse.ok(); attempt += 1) {
    await page.waitForTimeout(250);
    companyResponse = await page.request.post(`${apiUrl}/companies`, {
      headers,
      data: { name: companyName, location: "Oslo and remote across Europe", source: "direct" },
    });
  }
  const company = await companyResponse.json();
  expect(companyResponse.ok(), `company create failed: ${companyResponse.status()} ${JSON.stringify(company)}`).toBeTruthy();

  const jobData = {
    jobTitle: title,
    companyId: company.id,
    status: "Applied",
    location: "Oslo and remote across Europe",
    salary: null,
    salaryMin: null,
    salaryMax: null,
    salaryCurrency: null,
    salaryPeriod: null,
    nextAction: "Prepare a concise application answer",
    followUpAt: null,
    notes: "Ask about platform ownership and the incident response rotation.",
    description: `Build reliable distributed systems. ${"Long responsibility text ".repeat(80)} https://example.test/${"very-long-path-segment/".repeat(12)}`,
    translatedDescription: null,
    descriptionLanguage: "en",
    tags: JSON.stringify([".NET", "Kubernetes", "Incident response"]),
    deadline: null,
    coverLetterText: null,
    jobUrl: "https://example.test/jobs/platform-reliability",
    dateApplied: new Date().toISOString(),
    feedbackRequestedAt: null,
    source: "direct",
    countryCode: "NO",
  };
  let jobResponse = await page.request.post(`${apiUrl}/jobapplications`, { headers, data: jobData });
  for (let attempt = 0; attempt < 2 && !jobResponse.ok(); attempt += 1) {
    await page.waitForTimeout(250);
    jobResponse = await page.request.post(`${apiUrl}/jobapplications`, { headers, data: jobData });
  }
  expect(jobResponse.ok()).toBeTruthy();
  const job = await jobResponse.json();

  await page.goto("/jobs");
  const applicationRow = page.getByRole("row", { name: new RegExp(`Open ${title}`, "i") });
  await applicationRow.focus();
  await page.keyboard.press("Enter");
  await expect(page).toHaveURL(new RegExp(`/jobs/${job.id}$`));
  await expect(page.getByRole("heading", { name: title })).toBeVisible();

  await page.goBack();
  await expect(page).toHaveURL(/\/jobs$/);
  await page.goForward();
  await expect(page).toHaveURL(new RegExp(`/jobs/${job.id}$`));

  const workspaceNav = page.getByRole("tablist", { name: "Workspace sections" });
  await workspaceNav.getByRole("tab", { name: "Cover Letter", exact: true }).click();
  await expect(page).toHaveURL(new RegExp(`/jobs/${job.id}\\?section=cover-letter$`));
  await page.getByLabel("Application answer", { exact: true }).fill("A reviewed answer that must not be lost.");
  await workspaceNav.getByRole("tab", { name: "Analysis", exact: true }).click();
  await expect(page.getByRole("dialog", { name: "Unsaved application changes" })).toBeVisible();
  await page.getByRole("button", { name: "Keep editing" }).click();
  await expect(page.getByLabel("Application answer", { exact: true })).toHaveValue("A reviewed answer that must not be lost.");
  await page.getByRole("button", { name: "Save application drafts" }).click();
  await expect(page.getByText("Unsaved changes")).toHaveCount(0);

  await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "light"));
  await page.reload();
  for (const width of [375, 768, 1440]) {
    await page.setViewportSize({ width, height: 900 });
    await expect(page.getByRole("heading", { name: title })).toBeVisible();
    const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
    expect(overflow).toBeLessThanOrEqual(1);
  }

  await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "dark"));
  await page.reload();
  await expect(page.getByLabel("Application answer", { exact: true })).toHaveValue("A reviewed answer that must not be lost.");
  await expect(page.locator("html")).toHaveAttribute("data-color-scheme", "dark");

  for (const width of [375, 768, 1440]) {
    await page.setViewportSize({ width, height: 900 });
    await expect(page.getByRole("heading", { name: title })).toBeVisible();
    const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
    expect(overflow).toBeLessThanOrEqual(1);
  }

  await workspaceNav.getByRole("tab", { name: "Overview", exact: true }).click();
  await expect(page).toHaveURL(new RegExp(`/jobs/${job.id}\\?section=overview$`));
  await page.getByRole("button", { name: "Job details", exact: true }).click();
  await expect(page.getByText("Ask about platform ownership and the incident response rotation.")).toBeVisible();
  await expect(page.getByText("<<<APPLICATION_ANSWER_DRAFT>>>")).toHaveCount(0);

  await page.getByRole("button", { name: "Back to applications" }).click();
  await expect(page).toHaveURL(/\/jobs$/);
  await expect(page.getByRole("row", { name: new RegExp(`Open ${title}`, "i") })).toBeFocused();

  await page.goto("/jobs/2147483647");
  const missingJobAlert = page.getByRole("alert").filter({ hasText: /Not Found|Could not open this application/i });
  await expect(missingJobAlert).toBeVisible();
  const alertColours = await missingJobAlert.evaluate((element) => {
    const styles = window.getComputedStyle(element);
    const parentStyles = window.getComputedStyle(element.parentElement!);
    return {
      foreground: styles.color,
      background: styles.backgroundColor,
      parentBackground: parentStyles.backgroundColor,
    };
  });
  const alertBackground = composite(parseCssColour(alertColours.background), parseCssColour(alertColours.parentBackground));
  expect(contrastRatio(parseCssColour(alertColours.foreground), alertBackground)).toBeGreaterThanOrEqual(4.5);
  await expect(page.getByRole("button", { name: "Back to applications" })).toBeVisible();
});

test("Career Workspace loads from the authenticated application shell", async ({ page }) => {
  await login(page);
  await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "light"));
  await page.goto("/career");
  await expect(page.getByRole("heading", { name: "Career Workspace" })).toBeVisible();
  await expect(page.getByRole("link", { name: "Open CV Builder" })).toHaveAttribute("href", "/career/builder");

  await page.setViewportSize({ width: 375, height: 900 });
  const careerSection = page.getByRole("combobox", { name: "Career workspace section" });
  await expect(careerSection).toBeVisible();
  await careerSection.click();
  await page.getByRole("option", { name: "Career profile" }).click();
  await expect(page).toHaveURL(/\/career\?section=profile$/);
  await expect(page.getByRole("heading", { name: "Career profile" })).toBeVisible();
  await careerSection.click();
  await page.getByRole("option", { name: "Import review" }).click();
  await expect(page).toHaveURL(/\/career\?section=import$/);
  await expect(page.getByRole("heading", { name: "Master CV" })).toBeVisible();
  await careerSection.click();
  await page.getByRole("option", { name: "Overview" }).click();

  for (const width of [375, 768, 1440]) {
    await page.setViewportSize({ width, height: 900 });
    const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
    expect(overflow).toBeLessThanOrEqual(1);
  }

  await page.getByRole("link", { name: "Open CV Builder" }).click();
  await expect(page).toHaveURL(/\/career\/builder$/);
  await page.getByRole("button", { name: "New CV" }).first().click();
  await expect(page.getByRole("dialog", { name: "Create a CV" })).toBeVisible();
  await page.getByRole("button", { name: "Create CV" }).click();
  await expect(page).toHaveURL(/\/career\/builder\/\d+$/);
  await expect(page.getByLabel("CV name")).toBeVisible();

  await page.getByRole("tab", { name: "Content" }).click();
  await page.getByRole("button", { name: "Expand Professional Summary" }).click();
  await page.getByRole("button", { name: "Expand Experience" }).click();
  await expect(page.getByRole("button", { name: "Collapse Professional Summary" })).toHaveAttribute("aria-expanded", "true");
  await expect(page.getByRole("button", { name: "Collapse Experience" })).toHaveAttribute("aria-expanded", "true");

  await page.getByRole("button", { name: "Add content" }).click();
  const addContentDialog = page.getByRole("dialog", { name: "Add content" });
  const additionalExperienceCard = addContentDialog.getByRole("heading", { name: "Additional Experience" }).locator("..");
  await additionalExperienceCard.getByRole("button", { name: "Add", exact: true }).click();
  await page.getByRole("button", { name: "Expand Additional Experience" }).click();
  await page.getByRole("button", { name: "Add entry" }).click();
  await page.getByRole("textbox", { name: "Entry 1", exact: true }).fill("Maintained a community software project.");

  await page.getByRole("tab", { name: "Template" }).click();
  await page.getByRole("button").filter({ hasText: /^CodeTechnical/ }).click();
  await page.getByRole("tab", { name: "Customize" }).click();
  await page.getByLabel("Skills presentation").click();
  await page.getByRole("option", { name: "Bullet list" }).click();
  await page.locator('input[type="color"]').fill("#126b55");
  await expect(page.getByRole("tab", { name: "AI Tools" })).toBeVisible();

  await page.evaluate(() => window.localStorage.setItem("jobtracker.themeMode", "dark"));
  await page.reload();
  await expect(page.locator("html")).toHaveAttribute("data-color-scheme", "dark");
  for (const width of [375, 768, 1440]) {
    await page.setViewportSize({ width, height: 900 });
    await expect(page.getByLabel("CV name")).toBeVisible();
    if (width === 375) {
      await page.getByRole("button", { name: "Preview" }).click();
      await expect(page.getByTitle("CV preview page 1")).toBeVisible();
      await page.getByRole("button", { name: "Edit" }).click();
    }
    const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
    expect(overflow).toBeLessThanOrEqual(1);
  }
});

test("a public CV renders anonymously and downloads as PDF", async ({ page }, testInfo) => {
  await login(page);
  const headers = await csrfHeader(page);
  const create = await page.request.post(`${apiUrl}/cv/variants`, {
    headers,
    data: { name: "E2E Public CV" },
  });
  expect(create.ok()).toBeTruthy();
  const variant = await create.json();

  const publish = await page.request.put(`${apiUrl}/cv/variants/${variant.id}/public`, {
    headers,
    data: { isPublic: true },
  });
  expect(publish.ok()).toBeTruthy();
  const published = await publish.json();

  await page.context().clearCookies();
  await page.setViewportSize({ width: 375, height: 900 });
  await page.goto(`/cv/${published.publicSlug}`);
  const publicCvFrame = page.getByTitle("Public CV");
  await expect(publicCvFrame).toBeVisible();
  const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
  expect(overflow).toBeLessThanOrEqual(1);
  const publicCvMetrics = await publicCvFrame.evaluate((element) => {
    const frame = element as HTMLIFrameElement;
    return {
      renderedWidth: frame.getBoundingClientRect().width,
      innerOverflow: (frame.contentDocument?.documentElement.scrollWidth ?? 0) - (frame.contentDocument?.documentElement.clientWidth ?? 0),
    };
  });
  expect(publicCvMetrics.renderedWidth).toBeLessThanOrEqual(343);
  expect(publicCvMetrics.innerOverflow).toBeLessThanOrEqual(1);
  await expect(page.getByRole("link", { name: "Download PDF" })).toHaveAttribute("href", /\/pdf$/);
  const pdf = await page.request.get(`${apiUrl}/public-cv/${published.publicSlug}/pdf`);
  expect(pdf.ok()).toBeTruthy();
  expect(pdf.headers()["content-type"]).toContain("application/pdf");
  const pdfBody = await pdf.body();
  expect(pdfBody.length).toBeGreaterThan(1_000);
  expect(pdfBody.subarray(0, 5).toString()).toBe("%PDF-");
  await testInfo.attach("public-cv.pdf", { body: pdfBody, contentType: "application/pdf" });
});

test("the Code template exports a long structured CV as searchable multi-page PDF", async ({ page }, testInfo) => {
  await login(page);
  const headers = await csrfHeader(page);
  const longBullets = [
    "Designed resilient .NET services that processed high-volume workloads while preserving clear operational ownership and measurable service health.",
    "Improved deployment safety through automated checks, progressive delivery, actionable telemetry, and documented incident-response procedures.",
    "Collaborated with product, security, and support teams across Norway and the United Kingdom to turn ambiguous requirements into maintainable releases.",
  ];
  const profile = {
    version: "1",
    contact: {
      fullName: "Alex Eksempel",
      headline: "Principal Software Engineer",
      email: "alex.eksempel+career-verification@example.test",
      phone: "+47 412 34 567",
      location: "Oslo, Norge",
      website: "https://example.test/portfolio/with/a/deliberately/long/path",
      linkedIn: "https://linkedin.com/in/alex-eksempel",
      gitHub: "https://github.com/alex-eksempel",
    },
    summary: ["Teknisk leder med erfaring fra robuste plattformer, tilgjengelige tjenester og tverrfaglig produktutvikling."],
    jobs: Array.from({ length: 9 }, (_, index) => ({
      title: `Senior Platform Engineer ${index + 1} With A Deliberately Long Role Name`,
      company: `Example Technology Organisation ${index + 1} With A Long Employer Name`,
      location: index % 2 === 0 ? "Oslo, Norge" : "Warwickshire, United Kingdom",
      start: `${2015 + index}`,
      end: index === 8 ? "Present" : `${2016 + index}`,
      isCurrent: index === 8,
      bullets: longBullets,
      skills: ["C#", ".NET", "PostgreSQL", "Docker", "Azure DevOps"],
    })),
    education: [{ qualification: "BSc Software Engineering", institution: "Example University", start: "2011", end: "2015", details: ["Distributed systems and human-computer interaction"] }],
    certifications: [{ name: "Cloud Architecture Professional", issuer: "Example Institute", date: "2025" }],
    projects: [{ name: "Open Source Reliability Toolkit", role: "Maintainer", start: "2022", end: "Present", bullets: longBullets.slice(0, 2), skills: ["TypeScript", "Playwright"] }],
    skills: ["C# / .NET", "Python", "SQL", "Docker", "Azure DevOps", "Linux", "Observability", "Incident response"],
    languages: [{ name: "English", level: "Native" }, { name: "Norsk", level: "Profesjonelt arbeidsnivå" }],
    interests: ["Tilgjengelighet", "Open source"],
    otherSections: [{ title: "Additional Experience", items: ["Mentored early-career engineers", "Organised community technology workshops"] }],
  };

  const profileResponse = await page.request.put(`${apiUrl}/career/profile`, {
    headers,
    data: { profile, cvText: "Long sanitized CV fixture for PDF verification." },
  });
  expect(profileResponse.ok()).toBeTruthy();

  const create = await page.request.post(`${apiUrl}/cv/variants`, {
    headers,
    data: {
      name: "Code PDF Verification",
      settings: {
        themeId: "code",
        accent: "#0b7a63",
        pageSize: "a4",
        skillsStyle: "bullets",
        language: "nb",
      },
    },
  });
  const createBody = await create.text();
  expect(create.ok(), `CV create failed: ${create.status()} ${createBody}`).toBeTruthy();
  const variant = JSON.parse(createBody);

  const preview = await page.request.get(`${apiUrl}/cv/variants/${variant.id}/preview`);
  expect(preview.ok()).toBeTruthy();
  const previewBody = await preview.json();
  expect(previewBody.themeId).toBe("code");
  expect(previewBody.html).toContain("Alex Eksempel");
  expect(previewBody.html).toContain("--cv-accent-color:#0b7a63");

  await page.goto(`/career/builder/${variant.id}`);
  await expect(page.getByLabel("CV name")).toHaveValue("Code PDF Verification");
  await expect(page.getByRole("tab", { name: "Template" })).toHaveAttribute("aria-selected", "true");
  await page.getByRole("tab", { name: "Content" }).click();
  await page.getByRole("button", { name: "Expand Experience" }).click();
  await page.getByRole("button", { name: "Expand Education" }).click();
  await expect(page.getByRole("button", { name: "Collapse Experience" })).toBeVisible();
  await expect(page.getByRole("button", { name: "Collapse Education" })).toBeVisible();

  const addContentButton = page.getByRole("button", { name: "Add content" });
  await addContentButton.focus();
  await addContentButton.click();
  const addContentDialog = page.getByRole("dialog", { name: "Add content" });
  await expect(addContentDialog).toBeVisible();
  await expect(addContentDialog.getByRole("heading", { name: "Additional Experience" })).toBeVisible();
  await addContentDialog.getByRole("button", { name: "Cancel" }).click();
  await expect(addContentDialog).toBeHidden();
  await expect(addContentButton).toBeFocused();

  await page.getByRole("tab", { name: "Customize" }).click();
  await expect(page.getByLabel("Page size")).toBeVisible();
  await expect(page.getByLabel("Skills presentation")).toBeVisible();
  await page.getByRole("tab", { name: "AI Tools" }).click();
  await expect(page.getByText("Translate resume", { exact: true })).toBeVisible();
  await expect(page.getByText("Check spelling and grammar", { exact: true })).toBeVisible();

  for (const scheme of ["light", "dark"] as const) {
    await page.evaluate((value) => window.localStorage.setItem("jobtracker.themeMode", value), scheme);
    await page.reload();
    for (const width of [375, 768, 1440]) {
      await page.setViewportSize({ width, height: 900 });
      const overflow = await page.evaluate(() => document.documentElement.scrollWidth - document.documentElement.clientWidth);
      expect(overflow).toBeLessThanOrEqual(1);
    }
  }
  await expect(page.getByTitle("CV preview page 2")).toHaveCount(1, { timeout: 10_000 });
  const pagination = await page.getByTitle("CV preview", { exact: true }).evaluate((element) => {
    const frame = element as HTMLIFrameElement;
    const doc = frame.contentDocument;
    const height = 297 * 96 / 25.4;
    if (!doc || height <= 0) return { scriptRan: false, crossings: ["document unavailable"] };
    const topOf = (node: Element) => {
      let top = 0;
      let current = node as HTMLElement | null;
      while (current && current !== doc.body) {
        top += current.offsetTop || 0;
        current = current.offsetParent as HTMLElement | null;
      }
      return top;
    };
    const candidates = Array.from(doc.querySelectorAll<HTMLElement>(
      ".section:not(.section-flow),.section-flow > .entry:not(.entry-flow),.section-flow > .skill-groups > .skill-group,.section-flow > .bullets > li:not(.item-flow),.entry-flow .bullets > li:not(.item-flow)",
    ));
    const crossings = candidates.filter((candidate) => {
      const paddingTop = Number.parseFloat(getComputedStyle(candidate).paddingTop) || 0;
      const top = topOf(candidate) + paddingTop;
      const contentHeight = candidate.offsetHeight - paddingTop;
      const bottom = top + contentHeight;
      return contentHeight < height - 2
        && Math.floor((top + 1) / height) !== Math.floor((bottom - 1) / height);
    }).map((candidate) => ({
      className: candidate.className || candidate.tagName,
      top: topOf(candidate) + (Number.parseFloat(getComputedStyle(candidate).paddingTop) || 0),
      height: candidate.offsetHeight,
      paddingTop: getComputedStyle(candidate).paddingTop,
    }));
    return {
      scriptRan: !!doc.querySelector("script[data-cv-preview-pagination]"),
      crossings,
    };
  });
  expect(pagination.scriptRan).toBeTruthy();
  expect(pagination.crossings).toEqual([]);

  const pdf = await page.request.post(`${apiUrl}/cv/variants/${variant.id}/export-pdf`, { headers });
  expect(pdf.ok()).toBeTruthy();
  expect(pdf.headers()["content-type"]).toContain("application/pdf");
  const pdfBody = await pdf.body();
  expect(pdfBody.length).toBeGreaterThan(20_000);
  expect(pdfBody.subarray(0, 5).toString()).toBe("%PDF-");
  await testInfo.attach("code-long-cv.pdf", { body: pdfBody, contentType: "application/pdf" });
});
