#!/usr/bin/env node
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const child_process_1 = require("child_process");
const readline_1 = __importDefault(require("readline"));
const console_colors_1 = __importDefault(require("./console-colors"));
setInterval(() => {
    console.log(`Batchrun Running for ${process.uptime().toLocaleString()}s ...`);
}, 60000);
if ((_a = process.argv[process.argv.length - 1]) === null || _a === void 0 ? void 0 : _a.match(/^--version$|^-v$/)) {
    console.log(`Batchrun v${require("./package.json").version}`);
    process.exit();
}
const processesStrings = [];
let processes = [];
const isWindows = process.platform.match(/win/i);
const isMac = process.platform.match(/darwin/i);
const isLinux = process.platform.match(/linux/i);
////////////////////////////////////////////
////////////////////////////////////////////
////////////////////////////////////////////
const rl = readline_1.default.createInterface({
    input: process.stdin,
    output: process.stdout,
});
rl.on("line", (input) => {
    readCommands(input);
});
/**
 * Read Lines and execute commands
 * @param {string} input
 * @returns
 */
function readCommands(input) {
    if (input === null || input === void 0 ? void 0 : input.match(/^(reload|restart|reboot|r)$/i)) {
        console.log(` - ${console_colors_1.default.FgBlue}Reloading processes ...${console_colors_1.default.Reset}`);
        restartAll();
    }
    else if (input === null || input === void 0 ? void 0 : input.match(/^(reload|restart|reboot|r) \d/i)) {
        const processedIndexesString = input.split(" ")[1];
        const processedIndexes = processedIndexesString
            ? processedIndexesString.split(",")
            : null;
        if (!(processedIndexes === null || processedIndexes === void 0 ? void 0 : processedIndexes.length)) {
            console.log(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} No processes to reload`);
            return;
        }
        else {
            console.log(` - ${console_colors_1.default.FgBlue}Reloading processes ${processedIndexesString} ...${console_colors_1.default.Reset}`);
            processedIndexes.forEach((index) => {
                restartOne(parseInt(index));
            });
            console.log(` - ${console_colors_1.default.FgGreen}Processes Restarted Successfully ${processedIndexesString} ...${console_colors_1.default.Reset}`);
        }
    }
    if (input === null || input === void 0 ? void 0 : input.match(/^kill$/i)) {
        console.log(` - ${console_colors_1.default.FgYellow}Killing processes ...${console_colors_1.default.Reset}`);
        process.exit();
    }
    else if (input === null || input === void 0 ? void 0 : input.match(/^kill \d/i)) {
        const processedIndexesString = input.split(" ")[1];
        const processedIndexes = processedIndexesString
            ? processedIndexesString.split(",")
            : null;
        if (!(processedIndexes === null || processedIndexes === void 0 ? void 0 : processedIndexes.length)) {
            console.log(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} No processes to reload`);
            return;
        }
        else {
            console.log(` - ${console_colors_1.default.FgYellow}Killing processes ${processedIndexesString} ...${console_colors_1.default.Reset}`);
            processedIndexes.forEach((index) => {
                killOne(index);
            });
            console.log(` - ${console_colors_1.default.FgGreen}Processes Killed ${processedIndexesString} ...${console_colors_1.default.Reset}`);
        }
    }
}
process.stdin.on("keypress", (character, key) => {
    if (key.ctrl && key.name === "r") {
        console.log(` - ${console_colors_1.default.FgBlue}Reloading processes ...${console_colors_1.default.Reset}`);
        restartAll();
    }
});
/**
 * Cleanup function to kill all child processes
 */
function cleanupChildProcesses() {
    for (const childProcess of processes) {
        try {
            if (childProcess.pid) {
                console.log(` - ${console_colors_1.default.FgYellow}Killing process PID: ${childProcess.pid}${console_colors_1.default.Reset}`);
                killProcessForce(childProcess.pid);
            }
            childProcess.kill();
        }
        catch (error) {
            console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} Failed to kill process PID: ${childProcess.pid}`);
        }
    }
    processes = [];
}
process.on("exit", (code) => {
    console.log(` - ${console_colors_1.default.FgBlue}Process exited with code ${code}${console_colors_1.default.Reset}`);
    rl.close();
    cleanupChildProcesses();
});
process.on("SIGINT", () => {
    console.log(` - ${console_colors_1.default.FgYellow}SIGINT received, exiting...${console_colors_1.default.Reset}`);
    process.exit();
});
process.on("SIGTERM", () => {
    console.log(` - ${console_colors_1.default.FgYellow}SIGTERM received, exiting...${console_colors_1.default.Reset}`);
    process.exit();
});
////////////////////////////////////////////
////////////////////////////////////////////
////////////////////////////////////////////
const argvProcessListIndex = process.argv.indexOf("batch-run") + 1;
const argvProcessList = process.argv.at(-1);
const processesFilePath = path_1.default.resolve(process.cwd(), "batchrun.config.json");
if ((argvProcessList === null || argvProcessList === void 0 ? void 0 : argvProcessList.match(/batchrun/i)) && !fs_1.default.existsSync(processesFilePath)) {
    console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} No arguments to run`);
    process.exit(1);
}
if (fs_1.default.existsSync(processesFilePath)) {
    const processesFile = fs_1.default.readFileSync(processesFilePath, "utf8");
    const processesArray = JSON.parse(processesFile);
    for (let i = 0; i < processesArray.length; i++) {
        const processString = processesArray[i];
        const strippedProcessString = processString.trim();
        processesStrings.push(strippedProcessString);
    }
}
else if (argvProcessList) {
    const processesArray = argvProcessList.split(",");
    for (let i = 0; i < processesArray.length; i++) {
        const processString = processesArray[i];
        const strippedProcessString = processString.trim();
        processesStrings.push(strippedProcessString);
    }
}
else {
    console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} No arguments to run or \`batchrun.config.json\` file present`);
    process.exit(1);
}
if (!(processesStrings === null || processesStrings === void 0 ? void 0 : processesStrings[0])) {
    console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} No processes to run`);
    process.exit(1);
}
/** @type {import("child_process").SpawnOptions} */
const spawnOptions = {
    cwd: process.cwd(),
    shell: isWindows ? "bash.exe" : undefined,
    stdio: ["pipe", "inherit", "inherit"],
    detached: false,
};
/**
 * Start all processes
 */
function startProcesses() {
    for (let i = 0; i < processesStrings.length; i++) {
        const processString = processesStrings[i];
        const processStringArray = processString.split(" ");
        const targetProcess = processStringArray.shift();
        if (targetProcess) {
            const childProcess = (0, child_process_1.spawn)(targetProcess, processStringArray, spawnOptions);
            if (childProcess) {
                childProcess.on("exit", (code, signal) => {
                    console.log(` - ${console_colors_1.default.FgRed}Process ${i} exited with code ${code} and signal ${signal}${console_colors_1.default.Reset}`);
                });
                childProcess.on("error", (err) => {
                    console.error(` - ${console_colors_1.default.FgYellow}Error:${console_colors_1.default.Reset} Failed to start process ${i}: ${err.message}`);
                });
                childProcess.on("close", (code, signal) => {
                    console.log(` - ${console_colors_1.default.FgRed}Process ${i} closed with code ${code} and signal ${signal}${console_colors_1.default.Reset}`);
                });
                processes.push(childProcess);
            }
            else {
                console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} Failed to start process ${i}`);
                process.exit(1);
            }
        }
        else {
            console.error(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} A target process is not defined in \`${processString}\``);
            process.exit(1);
        }
    }
}
/**
 * Restart All Processes
 */
function restartAll() {
    for (let i = 0; i < processes.length; i++) {
        const childProcess = processes[i];
        try {
            if (childProcess.pid)
                killProcessForce(childProcess.pid);
            childProcess.kill();
            // processes.splice(i, 1);
        }
        catch (error) {
            console.log(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} Failed to kill process ${childProcess.pid}`);
            process.exit();
        }
    }
    console.log(` - ${console_colors_1.default.FgGreen}Restarted ${processes.length} processes${console_colors_1.default.Reset}`);
    processes = [];
    setTimeout(() => {
        startProcesses();
    }, 500);
}
/**
 * Restart a single process
 * @param {string} index
 */
function restartOne(index) {
    const childProcess = processes[index];
    try {
        if (childProcess.pid)
            killProcessForce(childProcess.pid);
        childProcess.kill();
    }
    catch (error) {
        console.log(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} Failed to kill process ${childProcess.pid}`);
        process.exit();
    }
    const processString = processesStrings[index];
    const processStringArray = processString.split(" ");
    const targetProcess = processStringArray.shift();
    if (!targetProcess)
        return;
    const newChildProcess = (0, child_process_1.spawn)(targetProcess, processStringArray, spawnOptions);
    processes.splice(index, 1, newChildProcess);
}
/**
 * Kill a single process
 * @param {string} index
 */
function killOne(index) {
    const childProcess = processes[parseInt(index)];
    if (childProcess.pid)
        killProcessForce(childProcess.pid);
    childProcess.kill();
    try {
    }
    catch (error) {
        console.log(` - ${console_colors_1.default.FgRed}Error:${console_colors_1.default.Reset} Failed to kill process ${childProcess.pid}`);
        process.exit();
    }
}
/**
 * Kill a process by PID
 * @param {number} pid
 */
function killProcessForce(pid) {
    if (typeof pid !== "number") {
        return;
    }
    try {
        if (isWindows) {
            (0, child_process_1.execSync)(`taskkill /F /PID ${pid} /T`);
        }
        else {
            (0, child_process_1.execSync)(`kill -9 ${pid}`);
        }
    }
    catch (error) { }
}
console.log(` - ${console_colors_1.default.FgGreen}Started ${processesStrings.length} processes${console_colors_1.default.Reset}`);
startProcesses();