import { expect, test } from "@playwright/test";
import { installMockApi } from "./mockApi";

test.beforeEach(async ({ page }) => {
  await installMockApi(page);
});

test("validation page: issues table, distributions and reason filter", async ({ page }) => {
  const issueRequests: string[] = [];
  page.on("request", (req) => {
    if (req.url().includes("/issues")) issueRequests.push(req.url());
  });

  await page.goto("/validation");

  // Both rejected objects are listed
  await expect(page.getByText("rsync://repo-a.example/ca1/stale.cer")).toBeVisible();
  await expect(page.getByText("rsync://repo-b.example/ca2/broken.roa")).toBeVisible();

  // Result distribution
  await expect(page.getByText("Result distribution")).toBeVisible();

  // Click a reject-reason row → URL param + filtered request
  await page.getByRole("button", { name: /manifest stale/ }).click();
  await expect(page).toHaveURL(/reason=manifest/);
  await expect.poll(() => issueRequests.some((u) => u.includes("reason=manifest"))).toBe(true);
  await expect(page.getByText("rsync://repo-b.example/ca2/broken.roa")).toBeVisible();
  await expect(page.getByText("rsync://repo-a.example/ca1/stale.cer")).toBeHidden();

  // Clear filters
  await page.getByRole("link", { name: "Clear filters" }).click();
  await expect(page.getByText("rsync://repo-a.example/ca1/stale.cer")).toBeVisible();
});

test("search page: grouped results and navigation", async ({ page }) => {
  await page.goto("/search?q=repo-a.example");
  await expect(page.getByText("Repositories (1)")).toBeVisible();
  await expect(page.getByText("Publication points (2)")).toBeVisible();

  await page.getByRole("link", { name: /repo-a.example/ }).first().click();
  await expect(page).toHaveURL(/\/repositories\/repo-a1b2c3d4e5f6|\/publication-points\/node_/);
});

test("search page: exact URI finds the object", async ({ page }) => {
  await page.goto("/search?q=rsync://repo-a.example/ca1/alice.roa");
  await expect(page.getByText("Objects (1)")).toBeVisible();
  await page.getByRole("link", { name: /alice.roa/ }).click();
  await expect(page).toHaveURL(/\/objects\/obj-roa-0001/);
});

test("search page: IP query runs a VRP lookup with pagination", async ({ page }) => {
  await page.goto("/search?q=81.68.1.1");
  await expect(page.getByRole("heading", { name: "VRP lookup" })).toBeVisible();

  // 61 matching fixture rows, page size 50 → first page shows row 1..50
  await expect(page.getByRole("cell", { name: "AS45090" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "81.68.0.0/14" }).first()).toBeVisible();
  await expect(page.getByText("Page 1 · 50 rows")).toBeVisible();

  await page.getByRole("button", { name: "Next" }).click();
  await expect(page.getByText("Page 2 · 11 rows")).toBeVisible();
  await expect(page.getByRole("cell", { name: "AS64570" })).toBeVisible();
  await page.getByRole("button", { name: "Previous" }).click();
  await expect(page.getByText("Page 1 · 50 rows")).toBeVisible();
});

test("search page: prefix query applies covering semantics", async ({ page }) => {
  // /14 VRPs have maxLength 14 < 16 and must NOT match a /16 query;
  // only the 81.68.0.0/16 maxLength 24 VRP covers it.
  await page.goto("/search?q=81.68.0.0/16");
  await expect(page.getByRole("heading", { name: "VRP lookup" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "AS64496" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "81.68.0.0/16" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "/24" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "AS45090" })).toHaveCount(0);
});

test("search page: IPv6 query returns the v6 VRP", async ({ page }) => {
  await page.goto("/search?q=2001:7fa:0:1::1");
  await expect(page.getByRole("cell", { name: "AS0", exact: true })).toBeVisible();
  await expect(page.getByRole("cell", { name: "2001:7fa:0:1::/64" })).toBeVisible();
});

test("search page: ASN filter narrows VRP results", async ({ page }) => {
  await page.goto("/search?q=81.68.1.1");
  await expect(page.getByRole("cell", { name: "AS45090" })).toBeVisible();

  await page.getByLabel("ASN filter").fill("AS64496");
  await page.getByRole("button", { name: "Apply" }).click();
  await expect(page).toHaveURL(/asn=64496/);
  await expect(page.getByRole("cell", { name: "AS64496" })).toBeVisible();
  await expect(page.getByRole("cell", { name: "AS45090" })).toHaveCount(0);
  await expect(page.getByText("Page 1 · 1 rows")).toBeVisible();
});

test("search page: invalid ASN filter shows an inline warning", async ({ page }) => {
  await page.goto("/search?q=81.68.1.1");
  await page.getByLabel("ASN filter").fill("AS123x");
  await page.getByRole("button", { name: "Apply" }).click();
  await expect(page.getByRole("status").filter({ hasText: "not a valid ASN" })).toBeVisible();
  await expect(page).not.toHaveURL(/asn=/);
});

test("search page: ASN-only query shows the API limitation notice", async ({ page }) => {
  await page.goto("/search?q=AS45090");
  await expect(
    page.getByRole("status").filter({ hasText: "cannot list VRPs by ASN alone" }),
  ).toBeVisible();
});

test("search page: empty result state", async ({ page }) => {
  await page.goto("/search?q=nothing-matches-this");
  await expect(page.getByText(/No results for/)).toBeVisible();
});

test("exports page: seeded job completes and offers a download", async ({ page }) => {
  const mock = await installMockApi(page);
  mock.seedJob({ status: "running" });

  await page.goto("/exports");
  await expect(page.getByText("job-0001")).toBeVisible();
  // Job transitions to complete after the poll interval
  await expect(page.getByRole("link", { name: "Download" })).toBeVisible({ timeout: 10_000 });
  await expect(page.getByText("2.0 KiB")).toBeVisible();
});
