import { execFile, spawn } from "node:child_process";
import { readFile } from "node:fs/promises";
import { join, resolve } from "node:path";
import { promisify } from "node:util";
import { developmentRuntimeEnvironment, installedRuntimeCleanupScript } from "./development-runtime-lib.mjs";
import { windowsCommand } from "./safe-runtime-lib.mjs";

const exec = promisify(execFile);
const sourceRoot = resolve(import.meta.dirname, "..");
const configPath = join(sourceRoot, "config.local.json");
const config = JSON.parse(await readFile(configPath, "utf8"));

if (process.platform === "win32") {
  await exec("powershell.exe", ["-NoProfile", "-Command", installedRuntimeCleanupScript()], {
    windowsHide: true,
    maxBuffer: 1024 * 1024
  });
}

const env = developmentRuntimeEnvironment(config, configPath, process.env);
const children = [
  start("backend", ["run", "dev:backend"]),
  start("pwa", ["run", "dev:pwa"])
];
let stopping = false;

function start(name, args) {
  const invocation = windowsCommand("npm.cmd", args);
  const child = spawn(invocation.command, invocation.args, {
    cwd: sourceRoot,
    env,
    windowsHide: true,
    stdio: "inherit"
  });
  child.runtimeName = name;
  return child;
}

async function stopChild(child) {
  if (!child || child.exitCode !== null) return;
  if (process.platform === "win32") {
    try { await exec("taskkill.exe", ["/pid", String(child.pid), "/t", "/f"], { windowsHide: true }); } catch {}
    return;
  }
  child.kill("SIGTERM");
}

async function stopAll() {
  if (stopping) return;
  stopping = true;
  await Promise.all(children.map(stopChild));
}

for (const signal of ["SIGINT", "SIGTERM"]) {
  process.on(signal, async () => {
    await stopAll();
    process.exit(0);
  });
}

const result = await Promise.race(children.map((child) => new Promise((resolveExit) => {
  child.once("error", (error) => resolveExit({ child, code: 1, error }));
  child.once("exit", (code) => resolveExit({ child, code: code ?? 1 }));
})));
await stopAll();
if (result.error) console.error(`${result.child.runtimeName} failed to start.`);
else if (result.code !== 0) console.error(`${result.child.runtimeName} stopped unexpectedly.`);
process.exitCode = result.code;
