#!/usr/bin/env node
/**
 * 一键启动：wolai-backend + 桌面端（Electron + 内置 Next standalone）
 *
 * 目的：
 * - 本地联调无需反复安装 NSIS 安装包
 * - Electron 走内置 Next（更接近安装包运行方式）
 *
 * 可选环境变量：
 * - SKIP_DESKTOP_NEXT_BUILD=1：跳过 build:desktop:next（仅启动）
 * - PYTHON_BIN：默认 python
 * - BACKEND_CMD：覆盖后端启动命令
 * - ELECTRON_CMD：覆盖 Electron 启动命令
 * - MNOTE_DATA_DIR：覆盖桌面端 data 目录（默认 <repo>/data-desktop-test）
 */

const { spawnSync, spawn } = require("child_process");
const fs = require("fs");
const net = require("net");
const path = require("path");

const rootDir = path.resolve(__dirname, "..");
const backendDir = path.join(rootDir, "wolai-backend");

function resolveBackendPython() {
  const fromEnv = (process.env.PYTHON_BIN || "").trim();
  if (fromEnv) return fromEnv;

  const isWin = process.platform === "win32";
  const candidates = isWin
    ? [
        path.join(backendDir, ".venv", "Scripts", "python.exe"),
        path.join(backendDir, ".venv312", "Scripts", "python.exe"),
        path.join(backendDir, "venv", "Scripts", "python.exe"),
      ]
    : [
        path.join(backendDir, ".venv-linux", "bin", "python"),
        path.join(backendDir, ".venv", "bin", "python"),
        path.join(backendDir, "venv", "bin", "python"),
      ];

  for (const candidate of candidates) {
    if (fs.existsSync(candidate)) {
      return candidate;
    }
  }

  return "python";
}

const pythonBin = resolveBackendPython();
const dataDir = process.env.MNOTE_DATA_DIR || path.join(rootDir, "data-desktop-test");

const backendCmd =
  process.env.BACKEND_CMD || `${pythonBin} -m uvicorn app.main:app --reload --host 127.0.0.1 --port 8000`;
const electronCmd = process.env.ELECTRON_CMD || "electron desktop-electron/main.js";

function loadEnvFile(filePath) {
  if (!fs.existsSync(filePath)) return {};
  const content = fs.readFileSync(filePath, "utf8");
  return content
    .split(/\r?\n/)
    .filter((line) => line.trim() && !line.trim().startsWith("#"))
    .reduce((acc, line) => {
      const idx = line.indexOf("=");
      if (idx === -1) return acc;
      const key = line.slice(0, idx).trim();
      const value = line.slice(idx + 1).trim();
      acc[key] = value;
      return acc;
    }, {});
}

function runOrExit(command, cwd, env) {
  const r = spawnSync(command, {
    cwd,
    env,
    stdio: "inherit",
    shell: true,
  });
  if (r.status !== 0) process.exit(r.status ?? 1);
}

async function waitForPort(host, port, timeoutMs = 20_000) {
  const start = Date.now();
  // eslint-disable-next-line no-constant-condition
  while (true) {
    const ok = await new Promise((resolve) => {
      const socket = net.createConnection({ host, port });
      const timer = setTimeout(() => {
        socket.destroy();
        resolve(false);
      }, 500);
      socket.once("connect", () => {
        clearTimeout(timer);
        socket.end();
        resolve(true);
      });
      socket.once("error", () => {
        clearTimeout(timer);
        resolve(false);
      });
    });
    if (ok) return;
    if (Date.now() - start > timeoutMs) {
      throw new Error(`等待端口超时：${host}:${port}`);
    }
    // eslint-disable-next-line no-await-in-loop
    await new Promise((r) => setTimeout(r, 120));
  }
}

async function main() {
  const envAllPath = path.join(rootDir, ".env.all");
  if (!fs.existsSync(envAllPath)) {
    console.error("[desktop-local] 缺少 .env.all：请在仓库根目录创建全局唯一 env 文件后重试。");
    process.exit(1);
  }

  const envMerged = {
    ...process.env,
    // 约定：全局仅使用仓库根目录的 .env.all 作为配置来源（生产优先）。
    ...loadEnvFile(envAllPath),
    PYTHONUTF8: "1",
    MNOTE_DATA_DIR: dataDir,
  };

  const skipBuild =
    (process.env.SKIP_DESKTOP_NEXT_BUILD || "").toLowerCase() === "1" ||
    (process.env.SKIP_DESKTOP_NEXT_BUILD || "").toLowerCase() === "true";

  if (!skipBuild) {
    console.log("[desktop-local] 构建桌面端内置 Next（standalone）…");
    runOrExit("pnpm run build:desktop:next", rootDir, envMerged);
  } else {
    console.log("[desktop-local] 已跳过 build:desktop:next（SKIP_DESKTOP_NEXT_BUILD=1）");
  }

  console.log(`[desktop-local] data 目录：${dataDir}`);
  console.log(`[desktop-local] 后端命令：${backendCmd}`);
  console.log(`[desktop-local] Electron 命令：${electronCmd}`);

  const children = [];
  let shuttingDown = false;

  const shutdown = () => {
    if (shuttingDown) return;
    shuttingDown = true;
    console.log("[desktop-local] 正在关闭子进程…");
    for (const child of children) {
      try {
        if (!child.killed) child.kill("SIGINT");
      } catch {}
    }
    setTimeout(() => process.exit(0), 200);
  };

  process.on("SIGINT", shutdown);
  process.on("SIGTERM", shutdown);

  const backend = spawn(backendCmd, {
    cwd: backendDir,
    env: envMerged,
    stdio: "inherit",
    shell: true,
  });
  children.push(backend);

  backend.on("exit", () => shutdown());

  await waitForPort("127.0.0.1", 8000).catch(() => {
    console.log("[desktop-local] 提示：未检测到后端 8000 端口就绪（可能仍在启动或启动失败）。");
  });

  const electron = spawn(electronCmd, {
    cwd: rootDir,
    env: envMerged,
    stdio: "inherit",
    shell: true,
  });
  children.push(electron);

  electron.on("exit", () => shutdown());
}

main().catch((err) => {
  console.error(err instanceof Error ? err.stack : String(err));
  process.exit(1);
});
