import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import { once } from "node:events";
import { test } from "node:test";

test("the packaged local launcher serves the calculator without npm", async (context) => {
  const child = spawn(process.execPath, ["scripts/serve-built.mjs", "--no-open", "--port=0"], {
    cwd: process.cwd(),
    stdio: ["ignore", "pipe", "pipe"],
  });
  context.after(() => {
    if (!child.killed) child.kill("SIGTERM");
  });

  let stderr = "";
  child.stderr.setEncoding("utf8");
  child.stderr.on("data", (chunk) => {
    stderr += chunk;
  });

  const url = await new Promise((resolve, reject) => {
    const timeout = setTimeout(() => reject(new Error(`launcher timeout\n${stderr}`)), 20_000);
    child.stdout.setEncoding("utf8");
    child.stdout.on("data", (chunk) => {
      const match = chunk.match(/http:\/\/127\.0\.0\.1:\d+\//);
      if (match) {
        clearTimeout(timeout);
        resolve(match[0]);
      }
    });
    child.once("exit", (code) => {
      clearTimeout(timeout);
      reject(new Error(`launcher exited with ${code}\n${stderr}`));
    });
  });

  const response = await fetch(url, { headers: { accept: "text/html" } });
  assert.equal(response.status, 200, stderr);
  const html = await response.text();
  assert.match(html, /Factorio Production Calculator/);

  const assetPath = html.match(/(?:src|href)="(\/assets\/[^"]+)"/)?.[1];
  assert.ok(assetPath, "rendered page must reference a built browser asset");
  const assetResponse = await fetch(new URL(assetPath, url));
  assert.equal(assetResponse.status, 200, assetPath);
  assert.ok(Number(assetResponse.headers.get("content-length")) > 0);

  child.kill("SIGTERM");
  await once(child, "exit");
});
