import fs from "node:fs";
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
import { loadDotEnv } from "../infra/dotenv.js";
import { normalizeEnv } from "../infra/env.js";
import { isMainModule } from "../infra/is-main.js";
import { ensureClawdbotCliOnPath } from "../infra/path-env.js";
import { assertSupportedRuntime } from "../infra/runtime-guard.js";
import { formatUncaughtError } from "../infra/errors.js";
import { installUnhandledRejectionHandler } from "../infra/unhandled-rejections.js";
import { enableConsoleCapture } from "../logging.js";
import { getPrimaryCommand } from "./argv.js";
import { tryRouteCli } from "./route.js";
export function rewriteUpdateFlagArgv(argv) {
    const index = argv.indexOf("--update");
    if (index === -1)
        return argv;
    const next = [...argv];
    next.splice(index, 1, "update");
    return next;
}
export async function runCli(argv = process.argv) {
    const normalizedArgv = stripWindowsNodeExec(argv);
    loadDotEnv({ quiet: true });
    normalizeEnv();
    process.env.OPENCLAW_MEDIA_ALLOW_ANY_LOCAL = "1";
    ensureClawdbotCliOnPath();
    // Enforce the minimum supported runtime before doing any work.
    assertSupportedRuntime();
    if (await tryRouteCli(normalizedArgv))
        return;
    // Capture all console output into structured logs while keeping stdout/stderr behavior.
    enableConsoleCapture();
    const { buildProgram } = await import("./program.js");
    const program = buildProgram();
    // Global error handlers to prevent silent crashes from unhandled rejections/exceptions.
    // These log the error and exit gracefully instead of crashing without trace.
    installUnhandledRejectionHandler();
    process.on("uncaughtException", (error) => {
        console.error("[openclaw-cn] Uncaught exception:", formatUncaughtError(error));
        process.exit(1);
    });
    const parseArgv = rewriteUpdateFlagArgv(normalizedArgv);
    // Register the primary subcommand if one exists (for lazy-loading)
    const primary = getPrimaryCommand(parseArgv);
    if (primary) {
        const { registerSubCliByName } = await import("./program/register.subclis.js");
        await registerSubCliByName(program, primary);
    }
    await program.parseAsync(parseArgv);
}
function stripWindowsNodeExec(argv) {
    if (process.platform !== "win32")
        return argv;
    const stripControlChars = (value) => {
        let out = "";
        for (let i = 0; i < value.length; i += 1) {
            const code = value.charCodeAt(i);
            if (code >= 32 && code !== 127) {
                out += value[i];
            }
        }
        return out;
    };
    const normalizeArg = (value) => stripControlChars(value)
        .replace(/^['"]+|['"]+$/g, "")
        .trim();
    const normalizeCandidate = (value) => normalizeArg(value).replace(/^\\\\\\?\\/, "");
    const execPath = normalizeCandidate(process.execPath);
    const execPathLower = execPath.toLowerCase();
    const execBase = path.basename(execPath).toLowerCase();
    const isExecPath = (value) => {
        if (!value)
            return false;
        const normalized = normalizeCandidate(value);
        if (!normalized)
            return false;
        const lower = normalized.toLowerCase();
        return (lower === execPathLower ||
            path.basename(lower) === execBase ||
            lower.endsWith("\\node.exe") ||
            lower.endsWith("/node.exe") ||
            lower.includes("node.exe") ||
            (path.basename(lower) === "node.exe" && fs.existsSync(normalized)));
    };
    const filtered = argv.filter((arg, index) => index === 0 || !isExecPath(arg));
    if (filtered.length < 3)
        return filtered;
    const cleaned = [...filtered];
    if (isExecPath(cleaned[1])) {
        cleaned.splice(1, 1);
    }
    if (isExecPath(cleaned[2])) {
        cleaned.splice(2, 1);
    }
    return cleaned;
}
export function isCliMainModule() {
    return isMainModule({ currentFile: fileURLToPath(import.meta.url) });
}
