/**
 * @license
 * Copyright 2022-2026 Greg Lauckhart <greg@lauckhart.com>
 * SPDX-License-Identifier: Apache-2.0
 */

import { spawn, SpawnOptions } from "node:child_process";
import { platform } from "node:os";

import colors from "ansi-colors";

export interface ExecuteOptions {
    env?: typeof process.env;
    cwd?: string;
}

export async function execute(bin: string, argv: string[], { env, cwd }: ExecuteOptions = {}) {
    return new Promise<number>((resolve, reject) => {
        let finished = false;

        const spawnOptions: SpawnOptions = {
            stdio: "inherit",
        };
        if (platform() === "win32") {
            spawnOptions.shell = true;
        }
        if (env !== undefined) {
            spawnOptions.env = { ...process.env, ...env };
        }
        if (cwd !== undefined) {
            spawnOptions.cwd = cwd;
        }

        const proc = spawn(bin, argv, spawnOptions);

        // Proxy SIGUSR2 to the child process
        process.on("SIGUSR2", () => {
            proc.kill("SIGUSR2");
        });

        proc.on("error", e => {
            finished = true;
            reject(e);
        });

        proc.on("close", code => {
            if (finished) {
                return;
            }
            finished = true;

            resolve(code ?? 1);
        });
    });
}

export async function executeNode(script: string, argv: string[], nodeArgv = Array<string>()) {
    const defaultNodeArgv = ["--enable-source-maps"];

    // Suppress "ExperimentalWarning" for features like node:sqlite that are stable enough for our use
    const [major] = process.versions.node.split(".");
    if (Number(major) >= 22) {
        defaultNodeArgv.push("--disable-warning=ExperimentalWarning");
    }

    argv = [...defaultNodeArgv, ...nodeArgv, script, ...argv];
    if (process.env.NACHO_RUN_ECHO) {
        const command = colors.whiteBright(`node ${argv.join(" ")}`);
        process.stdout.write(`${colors.greenBright("Execute:")} ${command}\n`);
    }
    return execute("node", argv, { env: {} });
}
