/* eslint-disable no-console */
import { SpawnOptionsWithoutStdio, spawn } from "node:child_process";

import { color } from "console-log-colors";

export const spawnPromise = (path, args?: string[], options?: SpawnOptionsWithoutStdio & { logCommand?: boolean, logData?: boolean, logError?: boolean, throwOnFail?: boolean }) => new Promise<{
    get all(): string;
    pid: number;
    status: number;
}>((resolve, reject) => {
    const all = [];
    const { logCommand = true, throwOnFail = false, logData = true, logError = true } = options ?? {};
    const cd = spawn(path, args, options);
    const pid = cd.pid;
    cd.stdout.on("data", (data) => {
        data = data.toString("utf8");
        all.push(data);
    });
    cd.stderr.on("data", (data) => {
        data = data.toString("utf8");
        all.push(color.red(data));
    });

    cd.on("error", (error) => {
        const errorText = color.red(error.stack ?? error.toString());
        all.push(error.stack ?? error.toString());
        if (logData || logError) {
            console.error(errorText);
        }
        reject(error);
    });
    cd.on("close", (status) => {
        if (status>0) {
            if (logError) {
                console.error(all);
            }
            if (throwOnFail) {
                reject(new Error(all.join("\n")));
                return;
            }
        }
        if (logCommand) {
            if (options.cwd) {
                console.log(`Spawn: ${path} in ${options.cwd} ${JSON.stringify(args, undefined, 2)}`);
            } else {
                console.log(`Spawn: ${path} ${JSON.stringify(args, undefined, 2)}`);
            }
            if (logData) {
                console.log(all.join("\n"));
            }
        }
        resolve({
            get all() {
                return all.join("\n");
            },
            pid,
            status });
    });
});
