/// <reference types="node" />

import { expect, test, type Page } from "@playwright/test";
import { readFile } from "node:fs/promises";

async function setEditor(page: Page, testId: string, value: string) {
  await page.getByTestId(testId).locator(".cm-content").fill(value);
}

async function waitForSyntax(page: Page) {
  await expect(
    page.getByRole("button", { name: "Run", exact: true }),
  ).toBeEnabled({ timeout: 15_000 });
}

test("deterministic generated cases are actual-engine verified and retain seed provenance", async ({
  page,
}) => {
  const pageErrors: string[] = [];
  page.on("pageerror", (error) => pageErrors.push(error.message));
  await page.goto("./");
  await page.getByLabel("Live").uncheck();
  await setEditor(
    page,
    "editor-regular-expression-pattern",
    "^(cat|dog)s{0,2}[A-Z]$",
  );
  await waitForSyntax(page);

  await page
    .getByRole("button", { name: "Generate cases", exact: true })
    .click();
  const dialog = page.getByRole("dialog", {
    name: "Generated test cases",
  });
  await expect(dialog).toBeVisible();
  await expect(dialog).toBeInViewport();
  await dialog
    .getByRole("textbox", { name: "Deterministic seed" })
    .fill("browser-seed-42");
  await dialog.getByRole("spinbutton", { name: "Seeded variants" }).fill("4");
  await dialog.getByRole("button", { name: "Generate & verify" }).click();

  const summary = dialog.getByRole("region", {
    name: "Generation summary",
  });
  await expect(summary).toContainText("Native ECMAScript RegExp", {
    timeout: 15_000,
  });
  await expect(summary).toContainText("browser-seed-42");
  const coverage = dialog.locator(".generation-coverage");
  await expect(
    coverage.getByText("alternative coverage", { exact: true }),
  ).toBeVisible();
  await expect(
    coverage.getByText("quantifier boundary", { exact: true }),
  ).toBeVisible();
  await expect(dialog.locator(".generated-case-list li").first()).toBeVisible();
  await expect(
    dialog.getByText("actual engine verified").first(),
  ).toBeVisible();
  await expect(dialog.getByText(/should match/u).first()).toBeVisible();
  await expect(dialog.getByText(/should not match/u).first()).toBeVisible();

  await dialog.getByRole("button", { name: "Add selected to tests" }).click();
  await expect(dialog).toContainText(
    /Added \d+ generated cases to the unit-test suite with seed provenance/u,
  );
  await dialog
    .getByRole("button", { name: "Close generated test cases" })
    .click();

  await page.getByRole("button", { name: "Unit tests", exact: true }).click();
  await expect(page.locator(".test-list li").first()).toContainText(
    "generated · seed browser-seed-42",
  );
  await page
    .getByRole("checkbox", { name: "Include subjects in JSON" })
    .check();
  const downloadPromise = page.waitForEvent("download");
  await page.getByRole("button", { name: "Export JSON" }).click();
  const download = await downloadPromise;
  const path = await download.path();
  if (!path) throw new Error("Generated test-suite download path unavailable");
  const suite = JSON.parse(await readFile(path, "utf8")) as {
    readonly tests: readonly {
      readonly subject: string;
      readonly generation?: {
        readonly seed?: string;
        readonly generatorId?: string;
      };
    }[];
  };
  expect(
    suite.tests.some(
      (candidate) =>
        candidate.subject.length > 0 &&
        candidate.generation?.seed === "browser-seed-42" &&
        candidate.generation.generatorId === "regex-tools-ast-cases",
    ),
  ).toBe(true);
  expect(pageErrors).toEqual([]);
});

test("PCRE2 reports generated cases unavailable instead of reusing ECMAScript semantics", async ({
  page,
}) => {
  await page.goto("./");
  await page.getByLabel("Live").uncheck();
  await page.getByRole("combobox", { name: "Flavour" }).selectOption("pcre2");
  await waitForSyntax(page);
  await page
    .getByRole("button", { name: "Generate cases", exact: true })
    .click();

  const dialog = page.getByRole("dialog", {
    name: "Generated test cases",
  });
  await expect(dialog).toContainText(
    "current PCRE2 syntax provider is intentionally partial",
  );
  await expect(
    dialog.getByRole("button", { name: "Generate & verify" }),
  ).toHaveCount(0);
});
