import fs from "fs";
import { ChildProcess } from "child_process";
import colors from "./console-colors";
import preflightFn from "./preflight";
import run from "./run";
import killChild from "./kill-child";

let childProcess: ChildProcess | null = null;

const pTitle = "buncid";
process.title = pTitle;

let timeout: any;

/**
 * # Start the process
 * @param {object} param0
 * @param {string} param0.command
 * @param {string[] | string} param0.preflight
 * @param {string[] | string} [param0.postflight]
 * @param {string} param0.redeploy_file
 * @param {string | number | (string | number)[]} [param0.port] - The port to kill on rebuild
 * @param {boolean} [param0.first_run] - Whether to run the preflight on first run. Default `false`
 */
export default function startProcess({
    command,
    preflight,
    postflight,
    redeploy_file,
    port,
    first_run,
    debounce,
}: {
    command: string;
    preflight?: string[] | string;
    postflight?: string[] | string;
    redeploy_file: string;
    port?: string | number | (string | number)[];
    first_run?: boolean;
    debounce?: number;
}) {
    const DEBOUNCE = debounce || 1000;

    try {
        if (first_run) {
            console.log("First Run ...");
            const runFirstPreflight = preflightFn(preflight);
        }

        childProcess = run(command);

        if (!childProcess) {
            console.log(
                `${colors.FgRed}Error:${colors.Reset} Process couldn't start. Exiting...`
            );
            process.exit();
        }

        console.log("Watching", redeploy_file);

        fs.watchFile(redeploy_file, { interval: 100 }, (curr, prev) => {
            if (global.DEPLOYING == 1) return;

            clearTimeout(timeout);

            timeout = setTimeout(() => {
                console.log(`${colors.BgBlue}File Changed${colors.Reset}`);

                if (global.REDEPLOYMENTS == 0) {
                    return;
                }

                global.DEPLOYING = 1;

                if (childProcess) {
                    console.log("******************************");
                    console.log(
                        `******** ${colors.FgBlue}Rebuilding ${colors.FgMagenta}${global.REDEPLOYMENTS}${colors.Reset} ********`
                    );
                    console.log("******************************");

                    try {
                        const runPreflight = preflightFn(preflight);

                        if (!runPreflight) {
                            console.log(
                                `${colors.FgRed}Error:${colors.Reset} Preflight Failed.`
                            );
                        } else {
                            killChild(childProcess, port).then((kill) => {
                                if (kill) {
                                    childProcess = run(command);

                                    if (postflight) {
                                        const runPostflight = preflightFn(
                                            postflight,
                                            true
                                        );

                                        if (!runPostflight) {
                                            console.log(
                                                `${colors.FgRed}Error:${colors.Reset} Postflight Failed.`
                                            );
                                        }
                                    }

                                    global.DEPLOYING = 0;
                                } else {
                                    process.exit();
                                }
                            });
                        }
                    } catch (error: any) {
                        console.log(
                            `${colors.FgRed}Error:${colors.Reset} killing child processes => ${error.message}`
                        );
                        process.exit();
                    }
                } else {
                    global.DEPLOYING = 0;
                }
            }, DEBOUNCE);
        });
    } catch (error: any) {
        console.log(
            `${colors.FgRed}Error:${colors.Reset} First run failed! => ${error.message}`
        );
    }
}