import { chromium } from "playwright";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const token = process.env.MAPBOX_PUBLIC_TOKEN;
if (!token?.startsWith("pk.")) {
  throw new Error("Set MAPBOX_PUBLIC_TOKEN to a public pk. token before running this script.");
}

const here = dirname(fileURLToPath(import.meta.url));
const evidenceDirectory = join(here, "..", "evidence");
const screenshotPath = join(evidenceDirectory, "mapbox-3d-city-live.png");
const diagnosticPath = join(evidenceDirectory, "mapbox-3d-city-diagnostic.png");
const evidencePath = join(evidenceDirectory, "mapbox-3d-city-evidence.json");
await mkdir(evidenceDirectory, { recursive: true });

const browser = await chromium.launch({
  channel: "chrome",
  headless: true,
  args: ["--enable-webgl", "--ignore-gpu-blocklist", "--use-angle=default"],
});

const context = await browser.newContext({
  viewport: { width: 1440, height: 900 },
  deviceScaleFactor: 1,
  colorScheme: "dark",
  reducedMotion: "no-preference",
});
const page = await context.newPage();
const pageErrors = [];
const networkFailures = [];
const redactTokens = (value) =>
  String(value).replace(/p[ks]\.[A-Za-z0-9._-]+/g, "[REDACTED_MAPBOX_TOKEN]");
page.on("pageerror", (error) => pageErrors.push(redactTokens(error.message)));
page.on("requestfailed", (request) => {
  const url = new URL(request.url());
  networkFailures.push({
    host: url.host,
    path: url.pathname,
    resourceType: request.resourceType(),
    error: request.failure()?.errorText || "unknown",
  });
});

try {
  await page.goto("http://127.0.0.1:4173/", {
    waitUntil: "commit",
    timeout: 15_000,
  });
  await page.waitForFunction(() => window.mapboxgl && document.querySelector("#status"), undefined, {
    timeout: 30_000,
  });
  await page.locator("#token").fill(token);
  await page.locator("#token-form button[type=submit]").click();

  await page.waitForFunction(
    () => document.querySelector("#status")?.textContent?.includes("First idle reached"),
    undefined,
    { timeout: 90_000 },
  );
  await page.waitForTimeout(1_500);

  await page.screenshot({ path: screenshotPath, fullPage: true });

  await page.locator("#benchmark").click();
  await page.waitForFunction(
    () => !document.querySelector("#export")?.disabled,
    undefined,
    { timeout: 20_000 },
  );

  await page.locator("#export").click();
  await page.waitForFunction(() => window.__mapboxReviewEvidence != null);
  const exportedEvidence = await page.evaluate(() => window.__mapboxReviewEvidence);
  const capturedEvidence = {
    ...exportedEvidence,
    capture: {
      browserMode: "headless",
      pageErrors,
      networkFailures,
    },
  };
  await writeFile(evidencePath, `${JSON.stringify(capturedEvidence, null, 2)}\n`, "utf8");

  const evidence = JSON.parse(await readFile(evidencePath, "utf8"));
  const result = {
    screenshot: screenshotPath,
    evidence: evidencePath,
    browserMode: "headless",
    libraryVersion: evidence.libraryVersion,
    city: evidence.city,
    viewport: evidence.viewport,
    webgl: evidence.webgl,
    firstIdleMs: evidence.firstIdleMs,
    frameTest: evidence.frameTest,
    exportedErrors: evidence.errors,
    pageErrors,
    networkFailures,
  };
  console.log(JSON.stringify(result, null, 2));

  if (pageErrors.length || evidence.errors.length) process.exitCode = 1;
} catch (error) {
  await page.screenshot({ path: diagnosticPath, fullPage: true }).catch(() => {});
  console.error(
    JSON.stringify(
      {
        error: redactTokens(error.message),
        status: await page.locator("#status").textContent().catch(() => null),
        tokenError: await page.locator("#token-error").textContent().catch(() => null),
        pageErrors,
        networkFailures,
        diagnostic: diagnosticPath,
      },
      null,
      2,
    ),
  );
  process.exitCode = 1;
} finally {
  await Promise.race([
    browser.close(),
    new Promise((resolve) => setTimeout(resolve, 5_000)),
  ]);
}
