import test from "node:test";
import assert from "node:assert/strict";
import { spawn } from "node:child_process";
import path from "node:path";
import { fileURLToPath } from "node:url";

const testDirectory = path.dirname(fileURLToPath(import.meta.url));
const brokerEntryPath = path.resolve(testDirectory, "../server.mjs");

test("server entrypoint starts the broker and stays alive until terminated", async () => {
  const child = spawn(process.execPath, [brokerEntryPath], {
    env: {
      ...process.env,
      PORT: "0",
      EDGE_AUTH_MODE: "stub",
    },
    stdio: ["ignore", "pipe", "pipe"],
  });

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

  await new Promise((resolve, reject) => {
    const timeout = setTimeout(() => {
      reject(new Error(`Broker entrypoint did not report readiness.\nstdout:\n${stdout}\nstderr:\n${stderr}`));
    }, 10_000);

    child.once("exit", (code, signal) => {
      clearTimeout(timeout);
      reject(new Error(`Broker entrypoint exited early with code=${code} signal=${signal}.\nstdout:\n${stdout}\nstderr:\n${stderr}`));
    });

    const poll = () => {
      if (/TruckWash edge broker listening on \d+/.test(stdout)) {
        clearTimeout(timeout);
        resolve();
        return;
      }
      setTimeout(poll, 25);
    };
    poll();
  });

  assert.equal(child.exitCode, null, `Broker exited unexpectedly.\nstdout:\n${stdout}\nstderr:\n${stderr}`);

  const exitResult = await new Promise((resolve, reject) => {
    child.once("exit", (code, signal) => resolve({ code, signal }));
    child.kill("SIGTERM");
    setTimeout(() => reject(new Error("Broker did not exit after SIGTERM.")), 10_000);
  });

  const exitedCleanly = exitResult.code === 0 || exitResult.signal === "SIGTERM";
  assert.equal(exitedCleanly, true, `Broker exited unsuccessfully.\nstdout:\n${stdout}\nstderr:\n${stderr}`);
});
