//#region imports
import { execSync } from 'child_process';
import { UtilsTerminal__NS__wait } from 'tnp-core/lib-prod';
import { startAsync, ___NS__isString, CoreModels__NS__BaseProjectTypeArr } from 'tnp-core/lib-prod';
export const BaseProjectTypeArr = CoreModels__NS__BaseProjectTypeArr;
//#endregion
//#region command config
export class CommandConfig {
    static from(config) {
        return new CommandConfig(config);
    }
    constructor(data) {
        Object.keys(data).forEach(key => {
            this[key] = data[key];
        });
    }
    name;
    cmd;
    headerMessageWhenActive;
    /**
     * If true, the output will be stored in a buffer and displayed when requested.
     * Default: true
     */
    useDataBuffer;
    /**
     * Process that should be started
     * before this process starts.
     */
    shouldBeActiveOrAlreadyBuild = [];
    goToNextCommandWhenOutput;
}
//#endregion
//#region command process state
export var CommandProcessState;
(function (CommandProcessState) {
    CommandProcessState["NOT_STARTED"] = "not-started";
    CommandProcessState["WAITING_TO_START"] = "waiting-to-start";
    CommandProcessState["RUNNING"] = "running";
    CommandProcessState["FINISHED_AND_RUNNING"] = "finished-and-running";
    CommandProcessState["FINISHED"] = "finished";
})(CommandProcessState || (CommandProcessState = {}));
//#endregion
//#region command process
export class CommandProcess {
    project;
    config;
    manager;
    //#region fields and getters
    state = CommandProcessState.NOT_STARTED;
    child_process;
    get cmd() {
        return this.config.cmd;
    }
    get name() {
        return this.config.name;
    }
    get headerMessageWhenActive() {
        return this.config.headerMessageWhenActive;
    }
    get pid() {
        return this.child_process.pid;
    }
    get isFinished() {
        return [
            CommandProcessState.FINISHED,
            CommandProcessState.FINISHED_AND_RUNNING,
        ].includes(this.state);
    }
    get isRunning() {
        return [
            CommandProcessState.RUNNING,
            CommandProcessState.FINISHED_AND_RUNNING,
        ].includes(this.state);
    }
    get isWaitingToStart() {
        return this.state === CommandProcessState.WAITING_TO_START;
    }
    markForStart() {
        if (this.isRunning || this.isWaitingToStart) {
            console.warn(`Already running or waiting to start: ${this.name}`);
            return;
        }
        this.state = CommandProcessState.WAITING_TO_START;
    }
    //#endregion
    dependenciesProcesses = [];
    //#region constructor
    constructor(project, config, manager) {
        this.project = project;
        this.config = config;
        this.manager = manager;
    }
    //#endregion
    //#region run
    async start(options) {
        //#region @backendFunc
        const { progress, resolveWhenFinish } = options || {};
        this.state = CommandProcessState.RUNNING;
        // console.log('Starting process:', this.name);
        await new Promise(async (resolve) => {
            const finishSyncCallback = async () => {
                if (resolveWhenFinish) {
                    resolve();
                }
                if (CommandProcessState.RUNNING) {
                    if (this.manager.watch) {
                        this.state = CommandProcessState.FINISHED_AND_RUNNING;
                    }
                    else {
                        this.state = CommandProcessState.FINISHED;
                    }
                }
            };
            // console.log(`Running command: ${this.cmd}`);
            await startAsync(this.cmd, this.project.location, {
                resolvePromiseMsg_stderr: ___NS__isString(this.config.goToNextCommandWhenOutput)
                    ? this.config.goToNextCommandWhenOutput
                    : this.config.goToNextCommandWhenOutput?.stderrContains,
                resolvePromiseMsg_stdout: ___NS__isString(this.config.goToNextCommandWhenOutput)
                    ? this.config.goToNextCommandWhenOutput
                    : this.config.goToNextCommandWhenOutput?.stdoutContains,
                biggerBuffer: true,
                resolvePromiseMsgCallback_anystd: () => {
                    finishSyncCallback();
                },
                onExitCallback: code => {
                    if (this.manager.watch) {
                        // TODO @LAST handle errors in watch mode
                        this.state = CommandProcessState.NOT_STARTED; // TODO maybe ERROR state better
                        this.manager.startedProcesses.delete(this);
                        resolve();
                    }
                    else {
                        process.exit(code); // exit main process
                    }
                },
                askToTryAgainOnError: true,
                onChildProcessChange: (child_process) => {
                    // @ts-expect-error overriding readonly property
                    this.child_process = child_process;
                },
                hideOutput_stderr: this.manager.hideOutput.stderr,
                hideOutput_stdout: this.manager.hideOutput.stdout,
                outputBuffer: this.manager.outputBuffer,
            });
            if (!resolveWhenFinish) {
                resolve();
            }
        });
        //#endregion
    }
    //#endregion
    //#region stop
    async stop() {
        //#region @backendFunc
        if (!this.manager.watch) {
            console.warn(`Can't stop process in normal mode: ${this.name}`);
            await UtilsTerminal__NS__wait(1);
            return;
        }
        this.state = CommandProcessState.NOT_STARTED;
        this.manager.startedProcesses.delete(this);
        if (![
            CommandProcessState.RUNNING,
            CommandProcessState.FINISHED_AND_RUNNING,
        ].includes(this.state)) {
            console.warn(`

        Can't stop process that is not running: ${this.name}

      `);
            await UtilsTerminal__NS__wait(1);
            return;
        }
        try {
            if (this.pid) {
                if (process.platform === 'win32') {
                    execSync(`taskkill /PID ${this.pid} /T /F`);
                }
                else {
                    process.kill(-this.pid);
                }
            }
        }
        catch (error) {
            console.error(`Error while stopping process: ${this.name}`);
            console.error(error);
        }
        //#endregion
    }
}
//#endregion
//# sourceMappingURL=c:/Users/darek/projects/npm/taon-dev/tnp-helpers/dist-nocutsrc-prod/lib/models.js.map