"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const cli_common_1 = require("../../cli-common");
const command_base_exec_1 = require("../../command-base-exec");
const codiac_constants_1 = require("../../codiac-constants");
class ClusterInstall extends command_base_exec_1.CommandBaseExec {
    constructor() {
        super(...arguments);
        this.infrxAliases = ["cluster:install"];
        this.adminOnly = true;
        this.versionsByAsset = {};
    }
    captureArgs() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(ClusterInstall);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if (args.cluster)
                partial.clusterName = args.cluster;
            if (flags.asset)
                partial.asset = flags.asset;
            if (flags.version)
                partial.version = 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)
                throw new Error('Cluster name is required in silent mode.');
            if (!partial.asset)
                throw new Error('Asset name is required in silent mode.');
            if (!partial.version)
                throw new Error('Asset version 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({ enterprise: partial.enterprise, clusterName: partial.clusterName, asset: partial.asset, version: partial.version }, (partial.wait ? { wait: true } : {}));
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            partial.clusterName = yield this.promptForClusterName(partial.clusterName, rootMap, takeDefaults);
            const ent = rootMap.enterprises.find(e => e.name === partial.enterprise);
            const asset = yield this.setAsset(partial.asset, ent, takeDefaults);
            partial.asset = asset.name;
            partial.version = yield this.setVersion(asset, partial.version, takeDefaults);
            return yield this.buildCandidate_silently(partial, rootMap);
        });
    }
    setAsset(userInput, ent, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let output;
            if (userInput !== codiac_constants_1.CliConstants.PROMPT_ME_DESIGNATOR) {
                const isValid = userInput != undefined && ent.assets.some(a => a.name === userInput);
                if (userInput && !isValid) {
                    this._ui.userMessage(this._styler.colorWarning(`Asset [${userInput}] not found in enterprise; please select from the list below.`));
                    userInput = undefined;
                }
                if (userInput) {
                    output = userInput;
                }
            }
            if (output == undefined) {
                let assetChanged;
                let assetType;
                [output, assetChanged, assetType] = yield this.rootMapUtils.promptForAsset(ent.assets, undefined);
            }
            return ent.assets.find(a => a.name === output);
        });
    }
    setVersion(asset, userInput, takeDefaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let output;
            let availables;
            if (userInput !== codiac_constants_1.CliConstants.PROMPT_ME_DESIGNATOR) {
                if (userInput != undefined) {
                    availables = yield this.loadAssetVersions(asset);
                    const isValid = availables.map(v => v.trim().toLowerCase()).includes(userInput.trim().toLowerCase());
                    if (!isValid) {
                        this._ui.userMessage(this._styler.colorWarning(`Version [${userInput}] not found; please select from the list below.`));
                        userInput = undefined;
                    }
                }
                if (userInput) {
                    output = userInput;
                    this._ui.userMessage(`Continuing with ${asset.name}:${output}`);
                }
            }
            if (output == undefined) {
                const sorted = availables !== null && availables !== void 0 ? availables : yield this.loadAssetVersions(asset);
                const fetchTags = (searchString) => tslib_1.__awaiter(this, void 0, void 0, function* () { return sorted.filter(v => v.toLowerCase().includes(searchString !== null && searchString !== void 0 ? searchString : '')).map(v => ({ name: v, value: v })); });
                const fuzzySelector = new cli_common_1.PromptSelectFuzzy(this.logger, this._ui, this._styler);
                output = yield fuzzySelector.go('assetVersion', 'Select the asset version:', false, undefined, false, fetchTags);
            }
            if (output == undefined)
                throw new Error(`No version was selected for asset [${asset.name}].`);
            return output;
        });
    }
    loadAssetVersions(asset) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (this.versionsByAsset[asset.name])
                return this.versionsByAsset[asset.name];
            this._ui.startSpinner('Loading versions...');
            const result = yield this.genRelayClient.Call.FetchAssetVersions({ image: asset.image, assetType: asset.type });
            if (result.error) {
                this._ui.stopSpinner('failed');
                throw result.error;
            }
            if (result.output)
                this.versionsByAsset[asset.name] = result.output;
            const sorted = (_a = this.versionsByAsset[asset.name]) !== null && _a !== void 0 ? _a : [];
            this._ui.stopSpinner(`found ${sorted.length}`);
            return sorted;
        });
    }
    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;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push('-e', candidate.enterprise);
        cmd.push(candidate.clusterName);
        cmd.push('-a', candidate.asset);
        cmd.push('-u', candidate.version);
        if (candidate.wait)
            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.assetDeploy({
                    spec: Object.assign({ target: {
                            enterprise: candidate.enterprise,
                            clusterName: candidate.clusterName,
                        }, assets: [{ a: candidate.asset, v: candidate.version }] }, (candidate.wait ? { wait: true } : {})),
                    socketId,
                    correlationId,
                }));
                if (result.error) {
                    const msg = `Error deploying [${candidate.asset}] to cluster [${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 = `Deployment failed for [${candidate.asset}] on cluster [${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!')} Deployed [${this._styler.hilite(candidate.asset)}] to cluster [${this._styler.hilite(candidate.clusterName)}].`;
                    this.logger.notice(msg, result);
                    this._ui.userMessage(msg);
                }
            }
            catch (err) {
                throw err;
            }
            finally {
                return;
            }
        });
    }
}
exports.default = ClusterInstall;
ClusterInstall.description = 'Deploys a given asset version to a cluster cabinet, using the async deployment pipeline.';
ClusterInstall.aliases = [];
ClusterInstall.examples = [
    {
        description: 'Deploy an asset to a cluster.',
        command: '<%= config.bin %> <%= command.id %> my-cluster -a my-chart -u 1.2.3',
    },
    {
        description: 'Deploy and wait for chart startup to complete.',
        command: '<%= config.bin %> <%= command.id %> my-cluster -a my-chart -u 1.2.3 --wait',
    },
    {
        description: 'Non-interactive (scripted) invocation.',
        command: '<%= config.bin %> <%= command.id %> my-cluster -a my-chart -u 1.2.3 --silent',
    },
];
ClusterInstall.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.' }),
    asset: core_1.Flags.string({ char: 'a', required: false, description: 'Name of the asset to deploy.' }),
    version: core_1.Flags.string({ char: 'u', required: false, dependsOn: ['asset'], description: 'Version of the asset to deploy.' }),
    wait: core_1.Flags.boolean({ required: false, description: 'Wait for all chart/asset startup to complete before returning. When omitted, returns 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.' }),
};
ClusterInstall.args = {
    cluster: core_1.Args.string({ description: 'Name of the cluster to deploy to.' }),
};
//# sourceMappingURL=install.js.map