"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const _ = require("lodash");
const command_base_exec_1 = require("../../../command-base-exec");
class ClusterStackInstall extends command_base_exec_1.CommandBaseExec {
    constructor() {
        super(...arguments);
        this.infrxAliases = ["cluster:stack:install"];
        this.adminOnly = true;
    }
    captureArgs() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(ClusterStackInstall);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if (args.cluster)
                partial.clusterName = args.cluster;
            if (flags.version)
                partial.stackVersion = flags.version;
            if (flags.wait)
                partial.wait = true;
            return [partial, false];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.clusterName || _.isEmpty(partial.clusterName)) {
                throw new Error("Cluster name is required in silent mode.");
            }
            const found = rootMap.clusters.find(c => c.name === partial.clusterName);
            if (!found)
                throw new Error(`No cluster found with name [${partial.clusterName}].`);
            return Object.assign(Object.assign({ enterprise: partial.enterprise, clusterName: partial.clusterName }, (partial.stackVersion ? { stackVersion: partial.stackVersion } : {})), (partial.wait !== undefined ? { wait: partial.wait } : {}));
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            partial.clusterName = yield this.promptForClusterName(partial.clusterName, rootMap, takeDefaults);
            partial.stackVersion = yield this.promptForStackVersion(partial.stackVersion, partial.enterprise, takeDefaults);
            return yield this.buildCandidate_silently(partial, rootMap);
        });
    }
    promptForClusterName(userInput, rootMap, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const clusters = rootMap.clusters.map(c => c);
            if (clusters.length === 0)
                throw new Error("No clusters found on this enterprise.");
            if (userInput) {
                const found = clusters.find(c => c.name === userInput);
                if (!found) {
                    this._ui.userMessage(this._styler.colorWarning(`No cluster found with name [${userInput}]; please select from the list below.`));
                    userInput = undefined;
                }
            }
            if (clusters.length === 1 && takeDefaults) {
                this._ui.userMessage(`Cluster: ${this._styler.hilite(clusters[0].name)}`);
                return clusters[0].name;
            }
            const selected = yield this.rootMapUtils.promptForCluster(clusters, userInput);
            return selected.name;
        });
    }
    promptForStackVersion(userInput, enterprise, takeDefaults) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (userInput) {
                this._ui.userMessage(`Stack version: ${this._styler.hilite(userInput)}`);
                return userInput;
            }
            this._ui.startSpinner("Retrieving available stack versions...");
            const result = yield this._codiacApi.EnterpriseVersionConfig.tryReadMany({
                enterprise,
                take: 100,
                sort: "created~desc",
            });
            if (result.error) {
                this._ui.stopSpinner("failed");
                throw result.error;
            }
            const snapshots = (_a = result.output) !== null && _a !== void 0 ? _a : [];
            this._ui.stopSpinner(`found ${snapshots.length}`);
            if (snapshots.length === 0) {
                this._ui.userMessage("No stack versions found. Proceeding with the default-tagged version.");
                return undefined;
            }
            const defaultSnapshot = snapshots.find(s => { var _a; return (_a = s.tags) === null || _a === void 0 ? void 0 : _a.some((t) => t.name === 'default'); });
            if (defaultSnapshot) {
                if (takeDefaults)
                    return undefined;
                const useDefault = yield this._ui.promptConfirm("useDefaultVersion", `Install the default stack version: ${this._styler.hilite(defaultSnapshot.version)}?`, true);
                if (useDefault)
                    return undefined;
            }
            else {
                this._ui.userMessage(this._styler.colorWarning("No snapshot is tagged as 'default'. Please select a version to install."));
            }
            const choices = snapshots.map(s => {
                var _a, _b;
                const dateStr = new Date(s.created).toISOString().split('T')[0];
                const tagStr = (_b = (_a = s.tags) === null || _a === void 0 ? void 0 : _a.map((t) => t.name).join(", ")) !== null && _b !== void 0 ? _b : "";
                const label = tagStr
                    ? `${s.version}  (${dateStr})  [${tagStr}]  by ${s.createdBy}`
                    : `${s.version}  (${dateStr})  by ${s.createdBy}`;
                return { name: label, value: s.version };
            });
            return yield this._ui.promptSelect("stackVersion", "Select a stack version to install:", choices);
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("-e", candidate.enterprise);
        cmd.push(candidate.clusterName);
        if (candidate.stackVersion)
            cmd.push("--version", candidate.stackVersion);
        if (candidate.wait === true)
            cmd.push("--wait");
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                const result = yield this.watcher.triggerAndWatch((correlationId, socketId) => this.genRelayClient.Call.clusterStackInstall({
                    spec: Object.assign(Object.assign({ clusterName: candidate.clusterName }, (candidate.stackVersion ? { stackVersion: candidate.stackVersion } : {})), (candidate.wait !== undefined ? { wait: candidate.wait } : {})),
                    socketId,
                    correlationId,
                }));
                if (result.error) {
                    const msg = `Error installing cluster stack on [${candidate.clusterName}]: ${(_a = result.message) !== null && _a !== void 0 ? _a : ""} ${(_b = result.error.message) !== null && _b !== void 0 ? _b : ""}`.trimEnd();
                    this.logger.error(msg, result.error);
                    this._ui.userMessage(`${this._styler.colorCritical("ERROR!")} ${msg}`);
                }
                else if (!result.success) {
                    const msg = `Cluster stack install failed on [${candidate.clusterName}]: ${(_c = result.message) !== null && _c !== void 0 ? _c : ""}`.trimEnd();
                    this.logger.notice(msg, result);
                    this._ui.userMessage(`${this._styler.colorCritical("FAILED!")} ${msg}`);
                }
                else {
                    const msg = `${this._styler.colorGood("SUCCESS!")} Cluster stack installed on [${this._styler.hilite(candidate.clusterName)}].`;
                    this.logger.notice(msg, result);
                    this._ui.userMessage(msg);
                }
            }
            catch (err) {
                throw err;
            }
            finally {
                return;
            }
        });
    }
}
exports.default = ClusterStackInstall;
ClusterStackInstall.description = 'Installs the cluster stack on the given cluster, deploying all infrastructure workloads defined in the stack snapshot.';
ClusterStackInstall.aliases = [];
ClusterStackInstall.examples = [
    {
        description: 'Install the default-tagged cluster stack version.',
        command: '<%= config.bin %> <%= command.id %> my-cluster',
    },
    {
        description: 'Install a specific cluster stack version.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --version 5CJRH7XB',
    },
    {
        description: 'Non-interactive (scripted) invocation.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --silent',
    },
    {
        description: 'Renders the equivalent silent command and then executes.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --echo',
    },
    {
        description: 'Render the equivalent silent command without executing.',
        command: '<%= config.bin %> <%= command.id %> my-cluster --to-script',
    },
];
ClusterStackInstall.flags = {
    help: core_1.Flags.help({ char: 'h', description: 'Displays the help document for this command.' }),
    enterprise: core_1.Flags.string({ char: 'e', required: false, description: 'Code name of the infrastructure enterprise to target.' }),
    version: core_1.Flags.string({ char: 'v', required: false, description: 'Version of the cluster stack snapshot to install. Omit to install the default-tagged version.' }),
    wait: core_1.Flags.boolean({ required: false, description: 'Wait for all helm chart startups to complete before returning. When omitted, helm installs return immediately without blocking on chart readiness.' }),
    silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Non-Interactive mode; executes without any user interaction and fails on any missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Echo interaction mode; renders the equivalent non-interactive cli command for future use before final execution.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Toscript interaction mode; renders the equivalent non-interactive cli command WITHOUT any execution.' }),
};
ClusterStackInstall.args = {
    cluster: core_1.Args.string({ description: 'Name of the cluster on which to install the stack.' }),
};
//# sourceMappingURL=install.js.map