import { fork } from "node:child_process";
import { resolve } from "node:path";
import { createInterface } from "node:readline/promises";
import { detectProject, hasDistBuild, resolveEntryFile, } from "./utils/detect-project.js";
import { resolvePreloads } from "./utils/preload.js";
async function promptPortConflictDecision(host, port, details) {
    if (!process.stdin.isTTY || !process.stdout.isTTY) {
        return "abort";
    }
    const rl = createInterface({
        input: process.stdin,
        output: process.stdout,
    });
    try {
        const owner = details?.pid
            ? ` pid=${details.pid}${details.command ? ` (${details.command})` : ""}`
            : "";
        const target = `${host ?? "0.0.0.0"}:${port}`;
        const answer = await rl.question(`[vextjs] Port ${target} is in use${owner}. Choose: [r]etry / [k]ill / [n]ext / [a]bort: `);
        switch (answer.trim().toLowerCase()) {
            case "r":
            case "retry":
                return "retry";
            case "k":
            case "kill":
                return "kill";
            case "n":
            case "next":
                return "next";
            default:
                return "abort";
        }
    }
    finally {
        rl.close();
    }
}
// ── 主函数 ──────────────────────────────────────────────────
/**
 * startCommand — vext start CLI 命令入口
 *
 * 解析命令行参数，检测项目结构，fork 子进程运行 bootstrap。
 *
 * @param args 命令行参数（如 ['--port', '8080']）
 */
export async function startCommand(args = []) {
    // ── 解析命令行参数 ────────────────────────────────────────
    const options = parseStartArgs(args);
    // ── 检测项目结构 ──────────────────────────────────────────
    const rootDir = resolve(process.cwd());
    const project = detectProject(rootDir);
    // ── 检测 dist/ 编译产物 ──────────────────────────────────
    const hasDist = hasDistBuild(project.rootDir);
    const entryFile = resolveEntryFile(project);
    // ── 打印启动信息 ──────────────────────────────────────────
    if (hasDist) {
        console.log("[vextjs] start mode - built (node, from dist/)");
    }
    else if (project.language === "ts") {
        console.log("[vextjs] start mode - TypeScript (tsx)");
    }
    else {
        console.log("[vextjs] start mode - JavaScript (node)");
    }
    // ── 构建子进程 execArgv ──────────────────────────────────
    //
    // execArgv 控制 Node.js 运行时参数（不是应用参数）：
    //   - dist/ 已编译 → 无需额外参数
    //   - TypeScript 项目 → --import tsx/esm（让 Node.js 能加载 .ts 文件）
    //   - JavaScript 项目 → 无需额外参数
    //
    const execArgv = [];
    if (!hasDist && project.language === "ts") {
        execArgv.push("--import", "tsx/esm");
    }
    // ── 注入预加载模块 ────────────────────────────────────
    //
    // 扫描直接依赖的 vext.preload 字段，将每个预加载文件以
    // --import <file:///...> 形式追加到 execArgv。
    // 无预加载包时返回 []，不追加任何参数，行为与旧版完全一致。
    //
    const preloads = await resolvePreloads(project.rootDir);
    for (const fileUrl of preloads) {
        execArgv.push("--import", fileUrl);
    }
    // ── 构建环境变量 ──────────────────────────────────────────
    const env = {
        ...process.env,
        NODE_ENV: process.env.NODE_ENV || "production",
        VEXT_MODE: "start",
        VEXT_ROOT: project.rootDir,
    };
    // dist/ 标记（bootstrap 可据此切换 srcDir）
    if (hasDist) {
        env.VEXT_BUILT = "1";
    }
    // 命令行参数覆盖（通过环境变量传递给 bootstrap）
    if (options.port !== undefined) {
        env.VEXT_PORT = String(options.port);
    }
    if (options.host !== undefined) {
        env.VEXT_HOST = options.host;
    }
    if (options.portConflict) {
        env.VEXT_PORT_CONFLICT = options.portConflict;
    }
    if (options.verboseLifecycle) {
        env.VEXT_LIFECYCLE_LEVEL = "verbose";
    }
    // ── fork 子进程 ──────────────────────────────────────────
    //
    // 使用 child_process.fork 而非 exec/spawn：
    //   - fork 创建新的 V8 实例，与 CLI 进程隔离
    //   - 支持 IPC 通信（未来 cluster 模式使用）
    //   - stdio: 'inherit' 共享 stdin/stdout/stderr
    //
    const child = fork(entryFile, [], {
        cwd: project.rootDir,
        execArgv,
        stdio: ["inherit", "inherit", "inherit", "ipc"],
        env,
    });
    child.on("message", async (msg) => {
        if (typeof msg !== "object" || msg === null) {
            return;
        }
        const payload = msg;
        if (payload.type === "port-conflict") {
            const action = await promptPortConflictDecision(payload.host, payload.port, payload.details);
            child.send({ type: "port-conflict-decision", action });
        }
    });
    // ── 子进程退出处理 ────────────────────────────────────────
    child.on("exit", (code, signal) => {
        if (signal) {
            // 被信号终止（如 SIGTERM）→ 正常退出
            process.exit(0);
        }
        // 使用子进程的退出码
        process.exit(code ?? 0);
    });
    // ── 子进程错误处理 ────────────────────────────────────────
    child.on("error", (err) => {
        console.error(`[vextjs] Failed to start child process: ${err.message}`);
        process.exit(1);
    });
    // ── 信号转发 ──────────────────────────────────────────────
    //
    // 将 CLI 进程收到的信号转发给子进程，
    // 触发子进程内 bootstrap 注册的优雅关闭流程。
    //
    // 使用 process.once（CLI 进程只需转发一次，
    // 后续由子进程的 exit 事件触发 CLI 进程退出）。
    //
    // 🐛 修复 BUG-014：Windows 上 child.kill('SIGTERM') 不会触发子进程的
    // process.on('SIGTERM') 处理器，而是直接通过 TerminateProcess API 杀死进程，
    // 导致 onClose hooks 不执行、DB 连接池不清理。
    //
    // 解决方案：Windows 上通过 IPC 消息 { type: 'shutdown' } 通知子进程
    // 执行优雅关闭流程。fork() 创建的子进程自带 IPC 通道，无需额外配置。
    // IPC 通道不可用时（child.connected === false）降级为 child.kill()。
    //
    const sendShutdown = () => {
        if (process.platform === "win32" && child.connected) {
            // Windows: 通过 IPC 通知子进程优雅关闭
            child.send({ type: "shutdown" });
            // 超时保护：如果子进程 15s 内未退出，强制终止
            setTimeout(() => {
                if (!child.killed) {
                    child.kill();
                }
            }, 15_000).unref();
        }
        else {
            // Unix: 标准 SIGTERM 信号（触发子进程 process.on('SIGTERM') 处理器）
            child.kill("SIGTERM");
        }
    };
    process.once("SIGTERM", sendShutdown);
    process.once("SIGINT", sendShutdown);
}
// ── 参数解析 ────────────────────────────────────────────────
/**
 * parseStartArgs — 解析 vext start 的命令行参数
 *
 * 支持的参数：
 *   --port <number>   覆盖监听端口
 *   --host <string>   覆盖监听地址
 *
 * 使用手动解析（不引入第三方 CLI 库），保持零依赖。
 *
 * @param args process.argv.slice(2) 的子集（已去除 'start' 命令本身）
 * @returns 解析后的选项
 */
function parseStartArgs(args) {
    const options = {};
    for (let i = 0; i < args.length; i++) {
        const arg = args[i];
        if (arg === "--port" && i + 1 < args.length) {
            const portStr = args[++i];
            const port = parseInt(portStr, 10);
            if (Number.isNaN(port) || port < 0 || port > 65535) {
                console.error(`[vextjs] Invalid port number: "${portStr}"`);
                process.exit(1);
            }
            options.port = port;
        }
        else if (arg === "--host" && i + 1 < args.length) {
            options.host = args[++i];
        }
        else if (arg === "--port-conflict" && i + 1 < args.length) {
            const strategy = args[++i];
            if (strategy !== "error" &&
                strategy !== "prompt" &&
                strategy !== "kill" &&
                strategy !== "next") {
                console.error(`[vextjs] Invalid --port-conflict value: "${strategy}"`);
                process.exit(1);
            }
            options.portConflict = strategy;
        }
        else if (arg === "--verbose-lifecycle") {
            options.verboseLifecycle = true;
        }
        else if (arg === "--help" || arg === "-h") {
            printStartHelp();
            process.exit(0);
        }
        else if (arg?.startsWith("--")) {
            console.error(`[vextjs] Unknown option: "${arg}"\n`);
            printStartHelp();
            process.exit(1);
        }
    }
    if (options.portConflict === undefined &&
        process.env.VEXT_PORT_CONFLICT &&
        ["error", "prompt", "kill", "next"].includes(process.env.VEXT_PORT_CONFLICT)) {
        options.portConflict = process.env.VEXT_PORT_CONFLICT;
    }
    if (options.verboseLifecycle === undefined &&
        process.env.VEXT_VERBOSE_LIFECYCLE === "1") {
        options.verboseLifecycle = true;
    }
    return options;
}
/**
 * 打印 vext start 的帮助信息
 */
function printStartHelp() {
    console.log(`
  Usage: vext start [options]

  Start the application in production mode.

  Options:
    --port <number>   Override the listening port
    --host <string>   Override the listening host
    --port-conflict <error|prompt|kill|next>
                       Configure how port conflicts are handled
    --verbose-lifecycle
                       Show verbose lifecycle logs
    -h, --help        Show this help message

  Examples:
    $ vext start
    $ vext start --port 8080
    $ vext start --host 127.0.0.1 --port 3000
    $ vext start --port-conflict prompt

  Environment variables:
    NODE_ENV          Set the environment (default: production)
    VEXT_CLUSTER=1    Enable cluster mode
    VEXT_PORT_CONFLICT=next
    VEXT_VERBOSE_LIFECYCLE=1
`);
}
