import { chromium } from "playwright"

// Start the Vite dev server (it serves the COOP/COEP headers needed for
// SharedArrayBuffer), drive real headless Chromium through both bench modes, and
// read the timings back. Real V8 + Web Workers + SAB + rAF -- the environment my
// headless Bun benches can't see.

const PORT = 5199
const URL = `http://localhost:${PORT}`

const vite = Bun.spawn(["bunx", "--bun", "vite", "--port", String(PORT), "--strictPort"], {
  cwd: import.meta.dir + "/..",
  stdout: "pipe",
  stderr: "pipe",
  env: { ...process.env, NO_COLOR: "1" },
})

async function waitForServer(): Promise<void> {
  for (let i = 0; i < 150; i++) {
    try {
      const r = await fetch(URL + "/")
      if (r.ok) {
        return
      }
    } catch {
      // not up yet
    }
    await Bun.sleep(200)
  }
  throw new Error("vite dev server did not start")
}

type Bench = {
  mode: string
  parallel: boolean
  cores: number
  coi: boolean
  res: string
  workMs: { median: number; p95: number; max: number; mean: number }
  frameMs: { median: number; p95: number; max: number; mean: number }
}

async function main(): Promise<void> {
  await waitForServer()
  const browser = await chromium.launch({
    headless: true,
    args: [
      "--enable-features=SharedArrayBuffer",
      "--disable-background-timer-throttling",
      "--disable-renderer-backgrounding",
      "--disable-backgrounding-occluded-windows",
    ],
  })

  async function run(mode: string): Promise<Bench> {
    const page = await browser.newPage()
    page.on("pageerror", (e) => console.log(`  [page error] ${e.message}`))
    page.on("console", (m) => {
      const t = m.text()
      if (t.startsWith("BENCH") || m.type() === "error") {
        console.log(`  [console] ${t}`)
      }
    })
    await page.setViewportSize({ width: 800, height: 600 })
    await page.goto(`${URL}/?bench=${mode}`, { waitUntil: "load" })
    await page.waitForFunction("window.__BENCH__ !== undefined", null, { timeout: 120000 })
    const result = (await page.evaluate("window.__BENCH__")) as Bench
    await page.close()
    return result
  }

  console.log("--- single-thread ---")
  const st = await run("st")
  console.log("--- workers ---")
  const mt = await run("mt")
  await browser.close()

  const line = (b: Bench) =>
    `parallel=${b.parallel} coi=${b.coi} cores=${b.cores} res=${b.res}  work med/p95/max = ${b.workMs.median}/${b.workMs.p95}/${b.workMs.max} ms  frame med/p95 = ${b.frameMs.median}/${b.frameMs.p95} ms`
  console.log("")
  console.log(`single-thread : ${line(st)}`)
  console.log(`workers       : ${line(mt)}`)
  console.log("")
  console.log(`work median   : ${st.workMs.median} -> ${mt.workMs.median} ms  (${(st.workMs.median / mt.workMs.median).toFixed(2)}x)`)
  console.log(`work p95      : ${st.workMs.p95} -> ${mt.workMs.p95} ms  (${(st.workMs.p95 / mt.workMs.p95).toFixed(2)}x)`)
  console.log(`frame p95     : ${st.frameMs.p95} -> ${mt.frameMs.p95} ms   (jitter: lower p95/median = steadier)`)
}

try {
  await main()
} finally {
  vite.kill()
}
