"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROMPT_ME_DESIGNATOR = void 0;
const tslib_1 = require("tslib");
require("reflect-metadata");
const core_1 = require("@oclif/core");
const command_base_exec_1 = require("../../command-base-exec");
exports.PROMPT_ME_DESIGNATOR = "?";
class AssetUndeploy extends command_base_exec_1.CommandBaseExec {
    constructor() {
        super(...arguments);
        this.infrxAliases = ["cluster:uninstall"];
    }
    captureArgs() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(AssetUndeploy);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            return [partial, false];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(AssetUndeploy);
            const enterprise = partial.enterprise;
            const ent = rootMap.enterprises.find(e => e.name === enterprise);
            if (!ent)
                throw new Error(`Enterprise "${enterprise}" not found.`);
            // Select asset
            let assetName;
            if (flags.asset && flags.asset !== exports.PROMPT_ME_DESIGNATOR) {
                const found = (_a = ent.assets) === null || _a === void 0 ? void 0 : _a.find(a => a.name === flags.asset);
                if (!found)
                    throw new Error(`Asset "${flags.asset}" not found in enterprise "${enterprise}".`);
                assetName = found.name;
            }
            else {
                const requestedAssets = yield this.establishAssetContext(ent, true);
                assetName = requestedAssets[0];
            }
            // Get deployment info for cabinet embellisher
            let embellisher;
            const resulte = yield this._codiacApi.Call.assetWhere({ enterprise, asset: assetName, rootMap });
            if (resulte.error != undefined)
                throw resulte.error;
            if (resulte.output)
                embellisher = this.createAssetVersionEmbellisher(resulte.output);
            // Select cabinet
            const [cab] = yield this.rootMapUtils.promptForCabinet(enterprise, rootMap, flags.cabinet, false, embellisher, flags.cabinet);
            const cabCntx = { enterprise: cab.enterprise, environment: cab.environment, cabinet: cab.name };
            // Establish cloud provider creds
            const cluster = (_b = cab.cluster) !== null && _b !== void 0 ? _b : ((rootMap.clusters.length === 1) ? rootMap.clusters[0].name : undefined);
            if (cluster === undefined) {
                this.logger.warn(`Cannot confirm cloud provider credentials: cabinet has no cluster specified. Process will rely on cached credentials.`);
            }
            else {
                yield this.establishCloudProviderCreds(rootMap, cluster);
            }
            return { enterprise, assetName, cabCntx, cluster };
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(AssetUndeploy);
            const enterprise = partial.enterprise;
            const ent = rootMap.enterprises.find(e => e.name === enterprise);
            if (!ent)
                throw new Error(`Enterprise "${enterprise}" not found.`);
            // Select asset
            let assetName;
            if (flags.asset === exports.PROMPT_ME_DESIGNATOR || !flags.asset) {
                const condemned = yield this.promptForAsset(enterprise, (_a = ent.assets) !== null && _a !== void 0 ? _a : []);
                assetName = condemned.name;
            }
            else {
                const condemned = yield this.promptForAsset(enterprise, (_b = ent.assets) !== null && _b !== void 0 ? _b : [], flags.asset);
                assetName = condemned.name;
            }
            // Get deployment info for cabinet embellisher
            let embellisher;
            const resulte = yield this._codiacApi.Call.assetWhere({ enterprise, asset: assetName, rootMap });
            if (resulte.error != undefined)
                throw resulte.error;
            if (resulte.output)
                embellisher = this.createAssetVersionEmbellisher(resulte.output);
            // Select cabinet
            const [cab] = yield this.rootMapUtils.promptForCabinet(enterprise, rootMap, flags.cabinet, false, embellisher, flags.cabinet);
            const cabCntx = { enterprise: cab.enterprise, environment: cab.environment, cabinet: cab.name };
            // Establish cloud provider creds
            const cluster = (_c = cab.cluster) !== null && _c !== void 0 ? _c : ((rootMap.clusters.length === 1) ? rootMap.clusters[0].name : undefined);
            if (cluster === undefined) {
                this.logger.warn(`Cannot confirm cloud provider credentials: cabinet has no cluster specified. Process will rely on cached credentials.`);
            }
            else {
                yield this.establishCloudProviderCreds(rootMap, cluster);
            }
            return { enterprise, assetName, cabCntx, cluster };
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("-e", candidate.enterprise);
        cmd.push("-a", candidate.assetName);
        cmd.push("-c", candidate.cabCntx.cabinet);
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this._ui.startSpinner(`Removing ${candidate.assetName} from ${candidate.cabCntx.cabinet}...`);
            const result = yield this.genRelayClient.Call.executeDestroyAssets({ target: candidate.cabCntx, assetsNames: [candidate.assetName] });
            this._ui.stopSpinner((result.success === true) ? "SUCCESS" : (result.error) ? "ERROR" : "DONE");
            if (result.error) {
                this.logger.error(`Error removing ${candidate.assetName} from ${candidate.cabCntx.cabinet}: ${result.message}`, result.error);
                this._ui.userMessage(`Error removing ${candidate.assetName} from ${candidate.cabCntx.cabinet}: ${result.message}`);
                throw result.error;
            }
            else if (result.success) {
                this.logger.notice(`Removed ${candidate.assetName} from ${candidate.cabCntx.cabinet}`);
                this._ui.userMessage(`Removed ${candidate.assetName} from ${candidate.cabCntx.cabinet}`);
            }
            else {
                const msg = (_a = result.message) !== null && _a !== void 0 ? _a : `Failed without error removing ${candidate.assetName} from ${candidate.cabCntx.cabinet}.`;
                this.logger.warn(msg, result);
                this._ui.userMessage(msg);
            }
        });
    }
    createAssetVersionEmbellisher(deployments) {
        return {
            eachEnterprise: (entBranch, ent, rootMap) => { },
            eachEnviro: (envBranch, env, ent, rootMap) => { },
            eachCabinet: (cabBranch, cab, env, ent, rootMap) => {
                const dep = deployments.find(d => d.cabinet === cab.name);
                if (dep === null || dep === void 0 ? void 0 : dep.assetVersion) {
                    const version = this._styler.dim("(".concat(dep.assetVersion, ")"));
                    cabBranch.text = cabBranch.text.concat("  ", version);
                }
            },
        };
    }
    promptForAsset(enterprise, assets, assetSearch) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (assets.length === 0)
                throw new Error(`The current enterprise [${enterprise}] has no assets defined.`);
            let selected;
            if (assetSearch && assetSearch !== exports.PROMPT_ME_DESIGNATOR) {
                selected = assets.find(a => a.name === assetSearch);
                if (!selected)
                    this._ui.userMessage(`The asset you specified was not found.`);
            }
            if (!selected) {
                if (assets.length === 1) {
                    const keepAsset = yield this._ui.promptConfirm('assetKeep', `Asset: ${this._styler.hilite(assets[0].name)}`, true);
                    if (keepAsset) {
                        selected = assets[0];
                    }
                    else {
                        this._ui.userMessage("No other assets available. Operation cancelled.");
                        this.exit(1);
                    }
                }
                else {
                    const choices = assets.map(a => ({ name: a.name, value: a.name }));
                    const assSelect = yield this._ui.promptSelectFuzzy('asset', 'Select an Asset:', () => tslib_1.__awaiter(this, void 0, void 0, function* () { return choices; }));
                    selected = assets.find(a => a.name === assSelect);
                }
            }
            if (!selected)
                throw new Error(`User failed to select a valid asset to destroy.`);
            return selected;
        });
    }
}
exports.default = AssetUndeploy;
AssetUndeploy.description = 'UN-deploys a given asset from a given cabinet.  Defaults to removing only the pod deployments and leaving the service in place; set the --scorch argument to remove the service.';
AssetUndeploy.aliases = ["cluster:uninstall"];
AssetUndeploy.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    enterprise: core_1.Flags.string({ char: 'e', required: false, description: 'Code (name) of the enterprise to work with (optional: required only when asset name is not unique across enterprises).' }),
    cabinet: core_1.Flags.string({ char: 'c', required: false, description: 'Name of the cabinet from which the asset is to be removed.' }),
    asset: core_1.Flags.string({ char: 'a', required: false, description: `Search string for the name of the asset to destroy (use ${exports.PROMPT_ME_DESIGNATOR} to be prompted).` }),
    version: core_1.Flags.string({ char: 'v', required: false, description: `Search string for the version of the asset to destroy (use ${exports.PROMPT_ME_DESIGNATOR} to be prompted).` }),
    scorch: core_1.Flags.boolean({ char: 's', required: false, description: 'Destroys the service too, instead of just the deployment and pods.' }),
    silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Executes without any user interaction; fails on missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Renders the equivalent non-interactive command for future use before executing.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Renders the equivalent non-interactive command without executing it.' }),
};
AssetUndeploy.args = {};
AssetUndeploy.examples = [
    { description: "Undeploy interactively.", command: "<%= config.bin %> <%= command.id %>" },
    { description: "Undeploy a specific asset from a specific cabinet.", command: "<%= config.bin %> <%= command.id %> -e myEnterprise -a myApi -c dev --silent" },
    { description: "Renders the equivalent silent command without executing.", command: "<%= config.bin %> <%= command.id %> -e myEnterprise -a myApi -c dev --to-script" },
];
//# sourceMappingURL=undeploy.js.map