import fs from "fs/promises";
import path from "path";
import { createServer } from "node:net";
import { generateManifest } from "@mandujs/core/router";
import {
  generateResourcesArtifacts,
  parseResourceSchemas,
  validateResourceUniqueness,
} from "@mandujs/core/resource";

const repoRoot = path.resolve(import.meta.dir, "..");
const baselinePath = path.join(repoRoot, "tests", "perf", "perf-baseline.json");
const benchmarkEntry = path.join(repoRoot, "packages", "core", "benchmark", "hydration-benchmark.ts");
const cliEntry = path.join(repoRoot, "packages", "cli", "src", "main.ts");
const bunExecutable = process.execPath;
const outputRoot = path.join(repoRoot, ".perf", "latest");
let browserBenchmarkUnavailableReason: string | null = null;

interface CompletedCommand {
  args: string[];
  cwd: string;
  exitCode: number;
  stdout: string;
  stderr: string;
}

interface RunningCommand {
  args: string[];
  cwd: string;
  proc: Bun.Subprocess<"pipe", "pipe", "inherit">;
  stdoutPromise: Promise<string>;
  stderrPromise: Promise<string>;
}

interface PerfBudgetEntry {
  budget: number;
  warningThresholdPct: number;
  baseline: number | null;
}

export interface PerfScenario {
  id: string;
  app: string;
  status: "active" | "manual" | "planned";
  mode: "dev" | "prod" | "build" | "hmr" | "streaming";
  url: string;
  runner: string;
  measuredMetrics: string[];
  budgets: Record<string, PerfBudgetEntry>;
  notes: string;
}

interface PerfBaseline {
  version: number;
  lastReviewed: string;
  metrics: Record<string, { unit: string; direction: string; description: string }>;
  scenarios: PerfScenario[];
  notes: string[];
}

interface BenchmarkStats {
  ttfb: { avg: number; min: number; max: number; p95: number };
  hydration: { avg: number; min: number; max: number; p95: number };
  bundleSize: { avg: number };
}

interface BenchmarkJson {
  timestamp: string;
  config: {
    url: string;
    runs: number;
    warmupRuns: number;
    throttle: "3G" | "4G" | "none";
  };
  stats: BenchmarkStats;
  raw: Array<Record<string, unknown>>;
}

export interface ScenarioMetrics {
  ssr_ttfb_p95_ms?: number;
  hydration_p95_ms?: number;
  initial_js_bundle_kb?: number;
  cold_start_p95_ms?: number;
  hmr_latency_p95_ms?: number;
  route_scan_p95_ms?: number;
  resource_generation_p95_ms?: number;
}

export interface MetricResult {
  metric: string;
  measured: number | null;
  budget: number;
  baseline: number | null;
  deltaFromBudget: number | null;
  deltaFromBaseline: number | null;
  regressionFromBaselinePct: number | null;
  regressionThresholdPct: number | null;
  failureReason: "budget" | "baseline-regression" | null;
  status: "pass" | "warn" | "fail" | "unsupported";
}

interface ScenarioResult {
  scenarioId: string;
  app: string;
  mode: string;
  url: string;
  benchmarkFile: string;
  warnings: string[];
  results: MetricResult[];
}

function parseArgs(argv: string[]): {
  scenarioIds: string[];
  runs: number;
  warmup: number;
  enforce: boolean;
} {
  const scenarioIds: string[] = [];
  let runs = 3;
  let warmup = 1;
  let enforce = false;

  for (let i = 0; i < argv.length; i++) {
    const arg = argv[i];
    if (arg === "--scenario") {
      const value = argv[i + 1];
      if (!value) {
        throw new Error("--scenario requires a scenario id");
      }
      scenarioIds.push(value);
      i += 1;
      continue;
    }
    if (arg === "--runs") {
      const value = argv[i + 1];
      if (!value) {
        throw new Error("--runs requires a number");
      }
      runs = parseInt(value);
      i += 1;
      continue;
    }
    if (arg === "--warmup") {
      const value = argv[i + 1];
      if (!value) {
        throw new Error("--warmup requires a number");
      }
      warmup = parseInt(value);
      i += 1;
      continue;
    }
    if (arg === "--enforce") {
      enforce = true;
      continue;
    }

    throw new Error(`Unknown argument: ${arg}`);
  }

  return { scenarioIds, runs, warmup, enforce };
}

async function readStream(stream: ReadableStream<Uint8Array> | null): Promise<string> {
  if (!stream) return "";
  return new Response(stream).text();
}

async function readStreamWithTimeout(promise: Promise<string>, timeoutMs = 2000): Promise<string> {
  return await Promise.race([
    promise,
    Bun.sleep(timeoutMs).then(() => "[stream capture timed out]"),
  ]);
}

async function killProcessTree(pid: number): Promise<void> {
  if (Bun.platform === "win32") {
    const killer = Bun.spawn(["taskkill", "/PID", String(pid), "/T", "/F"], {
      stdout: "ignore",
      stderr: "ignore",
    });
    await killer.exited;
    return;
  }

  try {
    process.kill(pid, "SIGTERM");
  } catch {
    // ignore
  }
}

async function cleanupWindowsProcessesByCommandFragments(fragments: string[]): Promise<void> {
  if (Bun.platform !== "win32" || fragments.length === 0) {
    return;
  }

  const conditions = fragments
    .map((fragment) => {
      const escaped = fragment.replace(/'/g, "''").replace(/\\/g, "\\\\");
      return `$_.CommandLine -like '*${escaped}*'`;
    })
    .join(" -or ");

  const script = [
    `$targets = Get-CimInstance Win32_Process | Where-Object { ${conditions} }`,
    "foreach ($target in $targets) {",
    "  try { taskkill /PID $target.ProcessId /T /F | Out-Null } catch {}",
    "}",
  ].join("; ");

  const proc = Bun.spawn(["powershell", "-NoLogo", "-NoProfile", "-Command", script], {
    stdout: "ignore",
    stderr: "ignore",
  });
  await proc.exited;
}

async function directoryExists(directory: string): Promise<boolean> {
  try {
    return (await fs.stat(directory)).isDirectory();
  } catch {
    return false;
  }
}

async function findFilesBySuffix(directory: string, suffix: string): Promise<string[]> {
  const files: string[] = [];

  async function walk(currentDirectory: string): Promise<void> {
    let entries: Array<{ name: string; isDirectory(): boolean; isFile(): boolean }>;
    try {
      entries = await fs.readdir(currentDirectory, { withFileTypes: true });
    } catch {
      return;
    }

    for (const entry of entries) {
      const fullPath = path.join(currentDirectory, entry.name);
      if (entry.isDirectory()) {
        await walk(fullPath);
        continue;
      }
      if (entry.isFile() && entry.name.endsWith(suffix)) {
        files.push(fullPath);
      }
    }
  }

  await walk(directory);
  return files.sort();
}

async function runCommand(
  args: string[],
  cwd: string,
  env: Record<string, string> = {}
): Promise<CompletedCommand> {
  const proc = Bun.spawn(args, {
    cwd,
    env: {
      ...process.env,
      ...env,
    },
    stdout: "pipe",
    stderr: "pipe",
  });

  const [stdout, stderr, exitCode] = await Promise.all([
    readStream(proc.stdout),
    readStream(proc.stderr),
    proc.exited,
  ]);

  const result: CompletedCommand = { args, cwd, exitCode, stdout, stderr };

  if (exitCode !== 0) {
    throw new Error(formatCommandFailure("Command failed", result));
  }

  return result;
}

function startCommand(
  args: string[],
  cwd: string,
  env: Record<string, string> = {}
): RunningCommand {
  const proc = Bun.spawn(args, {
    cwd,
    env: {
      ...process.env,
      ...env,
    },
    stdout: "pipe",
    stderr: "pipe",
  });

  return {
    args,
    cwd,
    proc,
    stdoutPromise: readStream(proc.stdout),
    stderrPromise: readStream(proc.stderr),
  };
}

async function stopCommand(command: RunningCommand): Promise<CompletedCommand> {
  await killProcessTree(command.proc.pid);

  const exitCode = await Promise.race([
    command.proc.exited,
    Bun.sleep(5000).then(() => -1),
  ]);
  const [stdout, stderr] = await Promise.all([
    readStreamWithTimeout(command.stdoutPromise),
    readStreamWithTimeout(command.stderrPromise),
  ]);

  return { args: command.args, cwd: command.cwd, exitCode, stdout, stderr };
}

function formatCommandFailure(prefix: string, result: CompletedCommand): string {
  const stdout = result.stdout.trim();
  const stderr = result.stderr.trim();

  return [
    prefix,
    `cwd: ${result.cwd}`,
    `command: ${result.args.join(" ")}`,
    `exitCode: ${result.exitCode}`,
    stdout ? `stdout:\n${stdout}` : "stdout:\n<empty>",
    stderr ? `stderr:\n${stderr}` : "stderr:\n<empty>",
  ].join("\n\n");
}

async function getFreePort(): Promise<number> {
  return await new Promise((resolve, reject) => {
    const server = createServer();

    server.on("error", reject);
    server.listen(0, "127.0.0.1", () => {
      const address = server.address();
      if (!address || typeof address !== "object") {
        server.close();
        reject(new Error("Failed to resolve a free port"));
        return;
      }

      const { port } = address;
      server.close((error) => {
        if (error) {
          reject(error);
          return;
        }
        resolve(port);
      });
    });
  });
}

async function waitForHttp(
  url: string,
  label: string,
  assertResponse: (response: Response) => Promise<void>,
  timeoutMs = 60_000
): Promise<void> {
  const startedAt = Date.now();
  let lastError: unknown;

  while (Date.now() - startedAt < timeoutMs) {
    try {
      const response = await fetch(url);
      await assertResponse(response);
      return;
    } catch (error) {
      lastError = error;
      await Bun.sleep(500);
    }
  }

  const reason = lastError instanceof Error ? lastError.message : String(lastError);
  throw new Error(`${label} did not become ready in ${timeoutMs}ms: ${reason}`);
}

async function assertHealthEndpoint(url: string): Promise<void> {
  await waitForHttp(url, "health endpoint", async (response) => {
    if (!response.ok) {
      throw new Error(`Expected 200 response, got ${response.status}`);
    }

    const data = await response.json() as { status?: string; framework?: string };
    if (data.status !== "ok") {
      throw new Error(`Unexpected health payload: ${JSON.stringify(data)}`);
    }
  });
}

function resolveScenarioUrl(baseOrigin: string, scenarioUrl: string): string {
  if (scenarioUrl.startsWith("http://") || scenarioUrl.startsWith("https://")) {
    const parsed = new URL(scenarioUrl);
    return new URL(`${parsed.pathname}${parsed.search}${parsed.hash}`, baseOrigin).toString();
  }

  return new URL(scenarioUrl, baseOrigin).toString();
}

function normalizeMetrics(benchmarkJson: BenchmarkJson): ScenarioMetrics {
  return {
    ssr_ttfb_p95_ms: benchmarkJson.stats.ttfb.p95,
    hydration_p95_ms: benchmarkJson.stats.hydration.p95,
    initial_js_bundle_kb: benchmarkJson.stats.bundleSize.avg,
  };
}

function calculateP95(values: number[]): number {
  const sorted = [...values].sort((a, b) => a - b);
  return sorted[Math.floor(sorted.length * 0.95)] ?? sorted[sorted.length - 1] ?? 0;
}

function extractInitialJsUrls(html: string, pageUrl: string): string[] {
  const resourceUrls = new Set<string>();
  const patterns = [
    /<script[^>]+src="([^"]+)"/g,
    /<link[^>]+rel="modulepreload"[^>]+href="([^"]+)"/g,
  ];

  for (const pattern of patterns) {
    let match: RegExpExecArray | null;
    while ((match = pattern.exec(html)) !== null) {
      const rawUrl = match[1];
      if (!rawUrl || !rawUrl.includes(".js")) continue;
      resourceUrls.add(new URL(rawUrl, pageUrl).toString());
    }
  }

  return [...resourceUrls];
}

async function measureHttpMetrics(url: string, runs: number): Promise<ScenarioMetrics> {
  const ttfbSamples: number[] = [];

  for (let i = 0; i < runs; i++) {
    const startedAt = performance.now();
    const response = await fetch(url, {
      headers: { "Cache-Control": "no-cache" },
    });

    if (!response.ok) {
      throw new Error(`Expected ${url} to return 200, got ${response.status}`);
    }

    ttfbSamples.push(performance.now() - startedAt);
    await response.text();
  }

  const htmlResponse = await fetch(url, {
    headers: { "Cache-Control": "no-cache" },
  });
  const html = await htmlResponse.text();
  const scriptUrls = extractInitialJsUrls(html, url);

  let bundleBytes = 0;
  for (const scriptUrl of scriptUrls) {
    const response = await fetch(scriptUrl, {
      headers: { "Cache-Control": "no-cache" },
    });
    if (!response.ok) continue;
    const body = await response.arrayBuffer();
    bundleBytes += body.byteLength;
  }

  return {
    ssr_ttfb_p95_ms: calculateP95(ttfbSamples),
    initial_js_bundle_kb: bundleBytes / 1024,
  };
}

async function measureRouteScanMetric(
  demoDir: string,
  scenarioOutputDir: string,
  runs: number,
): Promise<number> {
  const samples: number[] = [];
  const outputPath = path
    .relative(demoDir, path.join(scenarioOutputDir, "routes.manifest.json"))
    .replace(/\\/g, "/");

  for (let i = 0; i < runs; i++) {
    const startedAt = performance.now();
    await generateManifest(demoDir, { outputPath });
    samples.push(performance.now() - startedAt);
  }

  return calculateP95(samples);
}

async function measureResourceGenerationMetric(demoDir: string, runs: number): Promise<number | null> {
  const resourcesDir = path.join(demoDir, "spec", "resources");
  const resourceFiles = await findFilesBySuffix(resourcesDir, ".resource.ts");
  if (resourceFiles.length === 0) {
    return null;
  }

  const samples: number[] = [];
  for (let i = 0; i < runs; i++) {
    const startedAt = performance.now();
    const resources = await parseResourceSchemas(resourceFiles);
    validateResourceUniqueness(resources);
    await generateResourcesArtifacts(resources, {
      rootDir: demoDir,
      force: false,
      only: ["contract", "types", "client", "repo"],
    });
    samples.push(performance.now() - startedAt);
  }

  return calculateP95(samples);
}

async function measureProjectMetrics(
  scenario: PerfScenario,
  demoDir: string,
  scenarioOutputDir: string,
  runs: number,
): Promise<{ metrics: ScenarioMetrics; warnings: string[] }> {
  const metrics: ScenarioMetrics = {};
  const warnings: string[] = [];
  const sampleCount = Math.max(1, runs);

  if (scenario.measuredMetrics.includes("route_scan_p95_ms")) {
    metrics.route_scan_p95_ms = await measureRouteScanMetric(demoDir, scenarioOutputDir, sampleCount);
  }

  if (scenario.measuredMetrics.includes("resource_generation_p95_ms")) {
    try {
      const measured = await measureResourceGenerationMetric(demoDir, sampleCount);
      if (measured === null) {
        warnings.push("No spec/resources/**/*.resource.ts files found; resource generation metric is unsupported.");
      } else {
        metrics.resource_generation_p95_ms = measured;
      }
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      warnings.push("Resource generation benchmark was unavailable; metric is unsupported in this run.");
      await fs.writeFile(path.join(scenarioOutputDir, "resource-generation-error.txt"), `${message}\n`, "utf8");
    }
  }

  return { metrics, warnings };
}

const BASELINE_REGRESSION_THRESHOLD_PCT = 10;

export function compareScenarioMetrics(
  scenario: PerfScenario,
  metrics: ScenarioMetrics,
): MetricResult[] {
  return scenario.measuredMetrics.map((metric) => {
    const measured = metrics[metric as keyof ScenarioMetrics];
    const budgetEntry = scenario.budgets[metric];
    if (typeof measured !== "number" || Number.isNaN(measured)) {
      return {
        metric,
        measured: null,
        budget: budgetEntry.budget,
        baseline: budgetEntry.baseline,
        deltaFromBudget: null,
        deltaFromBaseline: null,
        regressionFromBaselinePct: null,
        regressionThresholdPct: budgetEntry.baseline === null ? null : BASELINE_REGRESSION_THRESHOLD_PCT,
        failureReason: null,
        status: "unsupported",
      };
    }

    const warningBudget = budgetEntry.budget * (1 - budgetEntry.warningThresholdPct / 100);
    const deltaFromBaseline = budgetEntry.baseline === null ? null : measured - budgetEntry.baseline;
    const regressionFromBaselinePct =
      budgetEntry.baseline !== null && budgetEntry.baseline > 0
        ? (deltaFromBaseline! / budgetEntry.baseline) * 100
        : null;
    const baselineRegression =
      regressionFromBaselinePct !== null &&
      regressionFromBaselinePct > BASELINE_REGRESSION_THRESHOLD_PCT;

    let status: MetricResult["status"] = "pass";
    let failureReason: MetricResult["failureReason"] = null;
    if (measured > budgetEntry.budget) {
      status = "fail";
      failureReason = "budget";
    } else if (baselineRegression) {
      status = "warn";
    } else if (measured > warningBudget) {
      status = "warn";
    }

    return {
      metric,
      measured,
      budget: budgetEntry.budget,
      baseline: budgetEntry.baseline,
      deltaFromBudget: measured - budgetEntry.budget,
      deltaFromBaseline,
      regressionFromBaselinePct,
      regressionThresholdPct: budgetEntry.baseline === null ? null : BASELINE_REGRESSION_THRESHOLD_PCT,
      failureReason,
      status,
    };
  });
}

function renderMarkdownReport(results: ScenarioResult[], generatedAt: string): string {
  const lines: string[] = [
    "# Mandu Performance Report",
    "",
    `Generated: ${generatedAt}`,
    "",
  ];

  for (const result of results) {
    lines.push(`## ${result.scenarioId}`);
    lines.push("");
    lines.push(`- App: \`${result.app}\``);
    lines.push(`- Mode: \`${result.mode}\``);
    lines.push(`- URL: \`${result.url}\``);
    lines.push(`- Benchmark JSON: \`${result.benchmarkFile}\``);
    for (const warning of result.warnings) {
      lines.push(`- Warning: ${warning}`);
    }
    lines.push("");
    lines.push("| Metric | Measured | Baseline | Δ baseline | Budget | Status | Reason |");
    lines.push("|---|---:|---:|---:|---:|---|---|");

    for (const metric of result.results) {
      lines.push(
        `| \`${metric.metric}\` | ${metric.measured === null ? "n/a" : metric.measured.toFixed(1)} | ${metric.baseline === null ? "n/a" : metric.baseline.toFixed(1)} | ${metric.regressionFromBaselinePct === null ? "n/a" : `${metric.regressionFromBaselinePct.toFixed(1)}%`} | ${metric.budget.toFixed(1)} | ${metric.status} | ${metric.failureReason ?? ""} |`
      );
    }

    lines.push("");
  }

  return lines.join("\n");
}

async function runScenarioBenchmark(
  scenario: PerfScenario,
  demoDir: string,
  runs: number,
  warmup: number,
): Promise<ScenarioResult> {
  const port = await getFreePort();
  const origin = `http://localhost:${port}`;
  const scenarioUrl = resolveScenarioUrl(origin, scenario.url);
  const scenarioOutputDir = path.join(outputRoot, scenario.id);
  const benchmarkJsonPath = path.join(scenarioOutputDir, "benchmark.json");
  const browserErrorPath = path.join(scenarioOutputDir, "browser-error.txt");
  const warnings: string[] = [];

  await fs.mkdir(scenarioOutputDir, { recursive: true });
  const projectResult = await measureProjectMetrics(scenario, demoDir, scenarioOutputDir, runs);
  warnings.push(...projectResult.warnings);

  if (scenario.mode === "prod") {
    console.log(`  build ${scenario.id}`);
    await runCommand([bunExecutable, "run", cliEntry, "build"], demoDir, {
      NODE_ENV: "production",
      PORT: String(port),
    });
  }

  const commandName = scenario.mode === "prod" ? "start" : "dev";
  console.log(`  start ${scenario.id} (${commandName}) on ${origin}`);
  const serverCommand = startCommand([bunExecutable, "run", cliEntry, commandName, `--port=${port}`], demoDir, {
    // Perf runs measure server/rendering behavior, not config lockfile policy.
    // Local demo worktrees may contain stale untracked .mandu/lockfile.json.
    MANDU_LOCK_BYPASS: "1",
    NODE_ENV: scenario.mode === "prod" ? "production" : "development",
    PORT: String(port),
  });

  try {
    await assertHealthEndpoint(`${origin}/api/health`);
    console.log(`  benchmark ${scenario.id} -> ${scenarioUrl}`);

    const httpMetrics = await measureHttpMetrics(scenarioUrl, runs);
    let browserMetrics: ScenarioMetrics = {};

    if (scenario.measuredMetrics.includes("hydration_p95_ms")) {
      if (browserBenchmarkUnavailableReason !== null) {
        warnings.push("Browser benchmark skipped after an earlier launch failure; hydration metric is unsupported in this run.");
        await fs.writeFile(browserErrorPath, `${browserBenchmarkUnavailableReason}\n`, "utf8");
      } else {
        try {
          await runCommand(
            [
              bunExecutable,
              "run",
              benchmarkEntry,
              scenarioUrl,
              String(runs),
              "none",
              "--warmup",
              String(warmup),
              "--wait-until",
              "load",
              "--json-out",
              benchmarkJsonPath,
            ],
            repoRoot,
          );
          console.log(`  benchmark complete ${scenario.id}`);
          const benchmarkJson = JSON.parse(await fs.readFile(benchmarkJsonPath, "utf8")) as BenchmarkJson;
          const normalizedBrowserMetrics = normalizeMetrics(benchmarkJson);
          browserMetrics = {
            hydration_p95_ms: normalizedBrowserMetrics.hydration_p95_ms,
          };
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error);
          browserBenchmarkUnavailableReason = message;
          warnings.push("Browser benchmark fallback was unavailable; hydration metric is unsupported in this run.");
          await fs.writeFile(browserErrorPath, `${message}\n`, "utf8");
          console.warn(`  browser benchmark unavailable for ${scenario.id}`);
        }
      }
    }

    const result = await stopCommand(serverCommand);
    await cleanupWindowsProcessesByCommandFragments([demoDir]);
    if (result.exitCode === -1) {
      warnings.push("Dev server process tree did not report a clean exit after perf collection.");
    }

    return {
      scenarioId: scenario.id,
      app: scenario.app,
      mode: scenario.mode,
      url: scenarioUrl,
      benchmarkFile: benchmarkJsonPath,
      warnings,
      results: compareScenarioMetrics(scenario, {
        ...projectResult.metrics,
        ...httpMetrics,
        ...browserMetrics,
      }),
    };
  } catch (error) {
    const result = await stopCommand(serverCommand);
    await cleanupWindowsProcessesByCommandFragments([demoDir]);
    throw new Error(
      `${error instanceof Error ? error.message : String(error)}\n\n${formatCommandFailure(
        "Perf server logs",
        result,
      )}`,
    );
  }
}

async function runBuildScenarioBenchmark(
  scenario: PerfScenario,
  demoDir: string,
  runs: number,
): Promise<ScenarioResult> {
  const scenarioOutputDir = path.join(outputRoot, scenario.id);
  const benchmarkJsonPath = path.join(scenarioOutputDir, "benchmark.json");

  await fs.mkdir(scenarioOutputDir, { recursive: true });
  const projectResult = await measureProjectMetrics(scenario, demoDir, scenarioOutputDir, runs);
  await fs.writeFile(
    benchmarkJsonPath,
    `${JSON.stringify({ metrics: projectResult.metrics, warnings: projectResult.warnings }, null, 2)}\n`,
    "utf8",
  );

  return {
    scenarioId: scenario.id,
    app: scenario.app,
    mode: scenario.mode,
    url: scenario.url,
    benchmarkFile: benchmarkJsonPath,
    warnings: projectResult.warnings,
    results: compareScenarioMetrics(scenario, projectResult.metrics),
  };
}

async function runHmrScenarioBenchmark(
  scenario: PerfScenario,
  runs: number,
): Promise<ScenarioResult> {
  const scenarioOutputDir = path.join(outputRoot, scenario.id);
  const benchmarkJsonPath = path.join(scenarioOutputDir, "hmr-benchmark.json");
  const warnings: string[] = [];

  await fs.mkdir(scenarioOutputDir, { recursive: true });
  const { runBenchmark } = await import("./hmr-bench");
  const measuresColdStart = scenario.measuredMetrics.includes("cold_start_p95_ms");
  const measuresHmrLatency = scenario.measuredMetrics.includes("hmr_latency_p95_ms");
  const report = await runBenchmark({
    iterations: measuresHmrLatency ? Math.max(1, runs) : 0,
    skipCold: !measuresColdStart,
    cellsOnly: "hybrid",
    writeReport: false,
  });

  const hmrMeasured = report.hardAssertions.islandP95Ms;
  const coldStartMeasured = report.hardAssertions.coldStartP95Ms;
  if (measuresHmrLatency && hmrMeasured === null) {
    warnings.push("HMR island latency was not measured by the hybrid benchmark subset.");
  }
  if (measuresColdStart && coldStartMeasured === null) {
    warnings.push("Cold start latency was not measured by the HMR benchmark harness.");
  }

  const metrics: ScenarioMetrics = {
    hmr_latency_p95_ms: hmrMeasured ?? undefined,
    cold_start_p95_ms: coldStartMeasured ?? undefined,
  };
  await fs.writeFile(
    benchmarkJsonPath,
    `${JSON.stringify({ hardAssertions: report.hardAssertions, runMeta: report.runMeta }, null, 2)}\n`,
    "utf8",
  );

  return {
    scenarioId: scenario.id,
    app: scenario.app,
    mode: scenario.mode,
    url: scenario.url,
    benchmarkFile: benchmarkJsonPath,
    warnings,
    results: compareScenarioMetrics(scenario, metrics),
  };
}

async function main(): Promise<number> {
  const { scenarioIds, runs, warmup, enforce } = parseArgs(process.argv.slice(2));
  const baseline = JSON.parse(await fs.readFile(baselinePath, "utf8")) as PerfBaseline;
  const runnableScenarios = baseline.scenarios.filter((scenario) => scenario.status !== "planned");
  const defaultScenarios = runnableScenarios.filter((scenario) => scenario.status === "active");
  const selectedScenarios = scenarioIds.length > 0
    ? runnableScenarios.filter((scenario) => scenarioIds.includes(scenario.id))
    : defaultScenarios;

  if (selectedScenarios.length === 0) {
    throw new Error("No active scenarios matched the requested filters");
  }

  const results: ScenarioResult[] = [];

  for (const scenario of selectedScenarios) {
    const demoDir = path.join(repoRoot, "demo", scenario.app);
    if (!await directoryExists(demoDir)) {
      throw new Error(`Active scenario '${scenario.id}' points to missing local demo '${scenario.app}' at ${demoDir}`);
    }

    console.log(`Running perf scenario: ${scenario.id}`);
    const result = scenario.mode === "build"
      ? await runBuildScenarioBenchmark(scenario, demoDir, runs)
      : scenario.mode === "hmr"
        ? await runHmrScenarioBenchmark(scenario, runs)
        : await runScenarioBenchmark(scenario, demoDir, runs, warmup);
    results.push(result);
  }

  await fs.mkdir(outputRoot, { recursive: true });
  const reportPath = path.join(outputRoot, "report.md");
  const summaryPath = path.join(outputRoot, "summary.json");
  const generatedAt = new Date().toISOString();
  const summary = {
    generatedAt,
    runs,
    warmup,
    enforce,
    scenarios: results,
  };

  await fs.writeFile(reportPath, `${renderMarkdownReport(results, generatedAt)}\n`, "utf8");
  await fs.writeFile(summaryPath, `${JSON.stringify(summary, null, 2)}\n`, "utf8");

  let hasFailure = false;
  for (const scenario of results) {
    for (const metric of scenario.results) {
      console.log(
        `${scenario.scenarioId} ${metric.metric}: ${metric.measured === null ? "n/a" : metric.measured.toFixed(1)} (baseline ${metric.baseline === null ? "n/a" : metric.baseline.toFixed(1)}, budget ${metric.budget.toFixed(1)}) -> ${metric.status}${metric.failureReason ? ` (${metric.failureReason})` : ""}`,
      );
      if (metric.status === "fail") {
        hasFailure = true;
      }
    }
  }

  console.log(`Saved perf summary to ${summaryPath}`);
  console.log(`Saved perf report to ${reportPath}`);

  if (enforce && hasFailure) {
    return 1;
  }

  return 0;
}

if (import.meta.main) {
  const exitCode = await main();
  process.exit(exitCode);
}
