import net from "node:net";
import { spawn } from "node:child_process";
import { fileURLToPath } from "node:url";
import { dirname, resolve } from "node:path";

const webRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const apiRoot = resolve(webRoot, "..", "API");
const apiHost = "127.0.0.1";
const apiPort = 8123;
const viteBin = resolve(webRoot, "node_modules", "vite", "bin", "vite.js");
let apiProcess;
let viteProcess;
let stopping = false;

function portOpen() {
  return new Promise(resolveResult => {
    const socket = net.createConnection({ host: apiHost, port: apiPort });
    const finish = open => {
      socket.destroy();
      resolveResult(open);
    };
    socket.once("connect", () => finish(true));
    socket.once("error", () => finish(false));
    socket.setTimeout(500, () => finish(false));
  });
}

async function waitForApi(timeoutMs = 120000) {
  const deadline = Date.now() + timeoutMs;
  while (Date.now() < deadline) {
    if (await portOpen()) return true;
    if (apiProcess?.exitCode != null) return false;
    await new Promise(resolveResult => setTimeout(resolveResult, 250));
  }
  return false;
}

function stop(code = 0) {
  if (stopping) return;
  stopping = true;
  viteProcess?.kill();
  apiProcess?.kill();
  process.exit(code);
}

process.once("SIGINT", () => stop(0));
process.once("SIGTERM", () => stop(0));

if (!(await portOpen())) {
  apiProcess = spawn("go", ["run", "./cmd/api"], {
    cwd: apiRoot,
    env: { ...process.env, SERVER_ADDRESS: `:${apiPort}` },
    stdio: "inherit",
    windowsHide: false,
  });
  apiProcess.once("error", error => {
    console.error(`启动 API 失败：${error.message}`);
    stop(1);
  });
}

if (!(await waitForApi())) {
  console.error(`API 未能在规定时间内监听 ${apiHost}:${apiPort}`);
  stop(1);
}

viteProcess = spawn(process.execPath, [viteBin, ...process.argv.slice(2)], {
  cwd: webRoot,
  stdio: "inherit",
  windowsHide: false,
});
viteProcess.once("error", error => {
  console.error(`启动 Vite 失败：${error.message}`);
  stop(1);
});
viteProcess.once("exit", code => stop(code ?? 0));
apiProcess?.once("exit", code => {
	if (!stopping) {
		console.error("API 进程已退出，停止 Vite。");
		stop(code || 1);
	}
});
