import AxeBuilder from "@axe-core/playwright";
import { expect, test } from "@playwright/test";
import { newIsolatedContext } from "./helpers";

async function expectAccessible(page: import("@playwright/test").Page): Promise<void> {
  const results = await new AxeBuilder({ page }).analyze();

  expect(
    results.violations,
    results.violations
      .map(
        (violation) =>
          `${violation.id}: ${violation.help}\n${violation.nodes
            .map((node) => `  ${node.target.join(" ")}: ${node.failureSummary}`)
            .join("\n")}`,
      )
      .join("\n\n"),
  ).toEqual([]);
}

test("public pages are accessible by keyboard in light and dark themes", async ({ browser }) => {
  const context = await newIsolatedContext(browser);
  const page = await context.newPage();

  await page.goto("/");
  await page.keyboard.press("Tab");
  await expect(page.getByRole("link", { name: "Skip to main content" })).toBeFocused();
  await page.keyboard.press("Enter");
  await expect(page.locator("#main-content")).toBeFocused();

  for (const theme of ["light", "dark"] as const) {
    await page.getByRole("button", { name: `Use ${theme} theme` }).click();
    await expect(page.locator("html")).toHaveAttribute("data-theme", theme);

    for (const path of ["/", "/safety", "/users/log-in", "/users/register"]) {
      await page.goto(path);
      await expectAccessible(page);
    }
  }

  await context.close();
});

test("public navigation does not overflow narrow or wide viewports", async ({ browser }) => {
  for (const viewport of [
    { width: 360, height: 800 },
    { width: 768, height: 1024 },
    { width: 1030, height: 900 },
    { width: 1440, height: 900 },
  ]) {
    const context = await newIsolatedContext(browser);
    const page = await context.newPage();
    await page.setViewportSize(viewport);
    await page.goto("/");

    const dimensions = await page.evaluate(() => ({
      clientWidth: document.documentElement.clientWidth,
      scrollWidth: document.documentElement.scrollWidth,
    }));

    expect(dimensions.scrollWidth).toBeLessThanOrEqual(dimensions.clientWidth);
    await expect(page.getByRole("navigation", { name: "Primary navigation" })).toBeVisible();

    await expect(page.locator("body > header")).toHaveCount(1);
    await expect(page.locator("body > nav[aria-label='Account and language']")).toHaveCount(0);

    if (viewport.width < 1280) {
      const menuButton = page.locator("summary[aria-label='Primary navigation']");
      await expect(menuButton).toBeVisible();
      await menuButton.click();

      await expect(page.getByRole("link", { name: "Requests", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Activities", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Categories", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Helpers", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "English", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Log in", exact: true })).toBeVisible();

      const openDimensions = await page.evaluate(() => ({
        clientWidth: document.documentElement.clientWidth,
        scrollWidth: document.documentElement.scrollWidth,
      }));

      expect(openDimensions.scrollWidth).toBeLessThanOrEqual(openDimensions.clientWidth);
    } else {
      await expect(page.locator("summary[aria-label='Primary navigation']")).toBeHidden();
      await expect(page.getByRole("link", { name: "Requests", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "English", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Register", exact: true })).toBeVisible();
      await expect(page.getByRole("link", { name: "Log in", exact: true })).toBeVisible();
    }

    await context.close();
  }
});
