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

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

test("object detail renders header metadata and parsed ROA projection", async ({ page }) => {
  await page.goto("/objects/obj-roa-0001");

  await expect(page.getByText("ROA object")).toBeVisible();
  await expect(page.getByText("rsync://repo-a.example/ca1/alice.roa").first()).toBeVisible();

  // Parsed tab is the default and renders structured ROA content
  await expect(page.getByText("AS ID")).toBeVisible();
  await expect(page.getByText("65001")).toBeVisible();
  await expect(page.getByText("203.0.113.0/24")).toBeVisible();
  await expect(page.getByText("2001:db8::/32")).toBeVisible();
});

test("tabs lazy-load: chain and validation requests fire only on activation", async ({ page }) => {
  const requests: string[] = [];
  page.on("request", (req) => requests.push(req.url()));

  await page.goto("/objects/obj-roa-0001");
  await expect(page.getByText("65001")).toBeVisible();
  expect(requests.some((u) => u.includes("/chain"))).toBe(false);
  expect(requests.some((u) => u.includes("/validation"))).toBe(false);

  await page.getByRole("tab", { name: "Chain" }).click();
  await expect.poll(() => requests.some((u) => u.includes("/chain"))).toBe(true);
  await expect(page.getByText("issued_by")).toBeVisible();

  await page.getByRole("tab", { name: "Validation" }).click();
  await expect.poll(() => requests.some((u) => u.includes("/validation"))).toBe(true);
  await expect(page.getByText("Final status")).toBeVisible();
});

test("validation explain POSTs and renders the audit-projection notice", async ({ page }) => {
  await page.goto("/objects/obj-roa-0001?tab=validation");
  const posts: string[] = [];
  page.on("request", (req) => {
    if (req.method() === "POST" && req.url().includes("/validation/explain")) posts.push(req.url());
  });

  await page.getByRole("button", { name: "Run explain" }).click();
  await expect.poll(() => posts.length).toBe(1);
  await expect(page.getByText("audit_projection").first()).toBeVisible();
  await expect(page.getByText("not a full revalidation")).toBeVisible();
});

test("CMS-signed ROA shows the EE Parsed tab with the embedded certificate", async ({ page }) => {
  await page.goto("/objects/obj-roa-0001");

  const eeTab = page.getByRole("tab", { name: "EE Parsed" });
  await expect(eeTab).toBeVisible();
  await eeTab.click();

  // EE certificate fields rendered like the Certificate object Parsed view.
  await expect(page.getByText("Serial number")).toBeVisible();
  await expect(page.getByText("0E65A501").first()).toBeVisible();
  await expect(page.getByText("CN=alice-roa-ee, serialNumber=0E65A501")).toBeVisible();
  await expect(page.getByText("CN=A9114E750000, serialNumber=5A179648")).toBeVisible();
  await expect(page.getByText("aa11bb22cc33dd44ee55ff66778899aabbccdd")).toBeVisible();
  await expect(page.getByText("203.0.113.0/24")).toBeVisible();
  await expect(page.getByText("AS65001", { exact: true })).toBeVisible();
  await expect(page.getByText("1.2.840.113549.1.1.11")).toBeVisible();
});

test("non-CMS objects do not show the EE Parsed tab", async ({ page }) => {
  await page.goto("/objects/obj-crl-0001");
  await expect(page.getByText("CRL number")).toBeVisible();
  await expect(page.getByRole("tab", { name: "EE Parsed" })).not.toBeVisible();

  await page.goto("/objects/obj-cer-0001");
  await expect(page.getByText("Serial number")).toBeVisible();
  await expect(page.getByRole("tab", { name: "EE Parsed" })).not.toBeVisible();
});

test("manifest object renders the file list", async ({ page }) => {  await page.goto("/objects/obj-mft-0001");
  await expect(page.getByText("Manifest number")).toBeVisible();
  await expect(page.getByText("0A2F")).toBeVisible();
  await expect(page.getByRole("cell", { name: "alice.roa" })).toBeVisible();
});

test("object without projection shows the explicit unavailable state", async ({ page }) => {
  await page.goto("/objects/obj-asa-0001");
  await expect(page.getByText("Parsed projection unavailable")).toBeVisible();
});

test("download raw triggers a browser download", async ({ page }) => {
  await page.goto("/objects/obj-roa-0001");
  const downloadPromise = page.waitForEvent("download");
  await page.getByRole("button", { name: "Download raw" }).click();
  const download = await downloadPromise;
  expect(download.suggestedFilename()).toBe("alice.roa");
});

test("export object set starts a job and offers the tarball when complete", async ({ page }) => {
  await page.goto("/objects/obj-roa-0001");
  const posts: string[] = [];
  page.on("request", (req) => {
    if (req.method() === "POST" && req.url().includes("/exports")) posts.push(req.url());
  });

  await page.getByRole("button", { name: "Export object set" }).click();
  await expect.poll(() => posts.length).toBe(1);
  // Mock completes the job after the first poll.
  await expect(page.getByRole("link", { name: "Download tar" })).toBeVisible({ timeout: 10_000 });
});

test("missing object shows an error state", async ({ page }) => {
  await page.goto("/objects/obj-does-not-exist");
  await expect(page.getByRole("alert")).toContainText("Failed to load object");
});
