"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const codiac_domain_1 = require("@codiac.io/codiac-domain");
const config_ui_utils_1 = require("../../../uilogic/config-ui-utils");
const command_base_exec_tenant_1 = require("../../../command-base-exec-tenant");
const type_safety_utils_1 = require("../../../uilogic/type-safety-utils");
const terminal_utils_1 = require("../../../ops/terminal-utils");
const local_command_runner_1 = require("../../../ops/terminal-command-runner/local-command-runner");
class NocClusterDestroy extends command_base_exec_tenant_1.CommandBaseExecTenant {
    get termUtils() {
        if (this._termUtils_backer === undefined) {
            this._termUtils_backer = this.ioc.get(terminal_utils_1.TerminalUtils); // new TerminalUtils(this.logger);
        }
        return this._termUtils_backer;
    }
    get localCommandRunner() {
        if (this._localCommandRunner_backer === undefined) {
            this._localCommandRunner_backer = this.ioc.get(local_command_runner_1.LocalCommandRunner); // new LocalCommandRunner(this.msgClient, this.cliEnviro, this.termUtils, this.logger); 
        }
        return this._localCommandRunner_backer;
    }
    bootstrap() {
        super.bootstrap();
        // CloudProviderContextualizer.bootstrap(this.ioc);  // this cant be double-booptstrapped.  Use the lazy property on CommandBaseEnterprise instead. 
        this.ioc.bind(terminal_utils_1.TerminalUtils).toDynamicValue(ctx => new terminal_utils_1.TerminalUtils(this.logger));
        this.ioc.bind(local_command_runner_1.LocalCommandRunner).toDynamicValue(ctx => new local_command_runner_1.LocalCommandRunner(this.msgClient, this.cliEnviro, this.termUtils, this.logger));
    }
    captureArgs() {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(NocClusterDestroy);
            const partial = {
                name: args.name,
                provider: flags.provider ? type_safety_utils_1.TypeSafetyUtils.toEnum(codiac_domain_1.CloudProviderEnum, flags.provider) : undefined,
                deleteIdentity: flags.deleteIdentity,
                partials: flags.partials,
                thisMachine: flags.local
            };
            const interactionMode = (_b = (_a = (flags.echo ? config_ui_utils_1.InteractionModes.echo : undefined)) !== null && _a !== void 0 ? _a : (flags["to-script"] ? config_ui_utils_1.InteractionModes.toscript : undefined)) !== null && _b !== void 0 ? _b : (flags.silent ? config_ui_utils_1.InteractionModes.silent : undefined);
            const takeDefaults = (_c = flags['take-defaults']) !== null && _c !== void 0 ? _c : false;
            return [partial, interactionMode, takeDefaults];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.name) {
                throw new Error("Required fields 'name' must be provided in silent mode.");
            }
            if (!partial.provider) {
                throw new Error("Required fields 'provider' must be provided in silent mode.");
            }
            // get subscription 
            let crit = { privateOwner: (_a = this._userCntx) === null || _a === void 0 ? void 0 : _a.currentTenantCode };
            let options = {
                projection: {
                    pathsIncluded: ["id", "name", "provider", "providerSubscription", "locationName", "privateOwner", "instance", "thisMachine", "modified", "modifiedBy"],
                    pathsExcluded: []
                }
            };
            if (partial.thisMachine)
                options.thisMachine = partial.thisMachine;
            let readResult = yield this._codiacApi.ClusterDef.tryReadMany(crit, options);
            let clusterDefs = (_b = readResult.output) !== null && _b !== void 0 ? _b : []; // we can only deinit clusters that have an instance
            const subx = (_c = clusterDefs.find(c => c.name == partial.name && c.provider == partial.provider)) === null || _c === void 0 ? void 0 : _c.providerSubscription;
            partial.providerSubscription = subx;
            return partial;
        });
    }
    buildCandidate_interactively(partial, takeDefaults, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let deleteIdentity = partial.deleteIdentity;
            let cluster;
            //Get cluster defs
            let crit = { privateOwner: (_a = this._userCntx) === null || _a === void 0 ? void 0 : _a.currentTenantCode };
            let options = {
                projection: {
                    pathsIncluded: ["id", "name", "provider", "providerSubscription", "locationName", "privateOwner", "instance", "thisMachine", "modified", "modifiedBy"],
                    pathsExcluded: []
                }
            };
            if (partial.thisMachine)
                options.thisMachine = partial.thisMachine;
            let readResult = yield this._codiacApi.ClusterDef.tryReadMany(crit, options);
            let clusterDefs = (_b = readResult.output) !== null && _b !== void 0 ? _b : []; // we can only deinit clusters that have an instance
            // only include partially created clusters if requested
            if (partial.partials !== true) {
                clusterDefs = clusterDefs.filter(c => c.instance != undefined);
            }
            // Only include clusters that match the provider if one was provided
            if (partial.provider && Object.keys(codiac_domain_1.CloudProviderEnum).indexOf(partial.provider) >= 0) {
                clusterDefs = clusterDefs.filter(c => c.provider == partial.provider);
            }
            if (readResult.error === undefined && clusterDefs.length === 0) {
                this._ui.userMessage("No ".concat((partial.thisMachine == true) ? "LOCAL" : "", " clusters exist with instances to destroy"));
                this.exit(0);
                return;
            }
            let candidate = {};
            if (partial.name)
                candidate.name = partial.name;
            let confirm = false;
            do {
                if (readResult.error) {
                    // if there is a problem with the cluster record, it may prevent a good read, 
                    // so we're going to allow the user to invoke the operation nonetheless.
                    let allPvds = this.cspUiFactory.getAllClusterProviders(this.ioc);
                    const csp = yield this.cspContextualizer.promptForCloudProvider(allPvds, undefined);
                    const name = (yield this._ui.prompt("clusterName", "Enter name of the cluster to destroy:", true));
                    const subx = (yield this._ui.prompt("clusterSubx", (csp == codiac_domain_1.CloudProviderEnum.aws ? "AccountId" : "SubscriptionId").concat(" of the cluster to deinitialize:"), true));
                    deleteIdentity = yield this._ui.promptConfirm("deleteIdentity", "Delete the cluster identity also?", false);
                    cluster = { name: name, provider: csp, providerSubscription: subx };
                }
                else { // if (readResult.success && readResult.output && readResult.output.length > 0) {
                    let found = (candidate.name) ? clusterDefs.find(c => c.name === candidate.name) : undefined;
                    if (found) {
                        cluster = found;
                    }
                    else {
                        let choices = clusterDefs
                            .map(c => { return { name: this.describeForList(c), value: c.name }; });
                        const name = (yield this._ui.promptSelect("clusterName", "Select the cluster to destroy:", choices));
                        let def = clusterDefs.find(c => c.name === name);
                        cluster = { name: name, provider: def.provider, providerSubscription: def.providerSubscription };
                    }
                }
                let also = (deleteIdentity == true) ? " and its identity" : "";
                confirm = yield this._ui.promptConfirm("confirmDestroy", `Destroy the physical cluster instance: ${this._styler.hilite(this.describe(cluster))}${also} ? `, false);
                if (!confirm)
                    candidate = {}; // if cluster was set as a cmd flag, but they denied the confirm, this allows selecting a different one.
            } while (confirm !== true);
            return cluster;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push(`--name=${candidate.name}`);
        cmd.push(`--provider=${candidate.provider}`);
        if (candidate.deleteIdentity)
            cmd.push('--deleteIdentity');
        if (candidate.partials == true)
            cmd.push('--partials');
        if (candidate.thisMachine == true)
            cmd.push('--local');
        cmd.push('--silent');
        return cmd;
    }
    executeTask(candidate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                if (candidate.provider == codiac_domain_1.CloudProviderEnum.localMachine) {
                    let socketId = yield this.msgClient.connect();
                    this.localCommandRunner.listen(); // to fire off any local machine terminal commands requested by the relay during the cluster create
                }
                yield this.cspContextualizer.promptForCloudProviderCreds(this.ioc, candidate.provider, undefined, undefined, undefined, candidate.providerSubscription);
                this._ui.startSpinner(`Destroying physical cluster instance: ${this._styler.hilite(candidate.name)}...`);
                const result = yield this.genRelayClient.Call.postExecuteDeleteClusterInstance({ name: candidate.name, deleteIdentity: candidate.deleteIdentity });
                this._ui.stopSpinner(result.success ? "SUCCESS" : "FAILED");
                const msg = `Cluster destroy ${result.success ? this._styler.colorGood("SUCCESS") : this._styler.colorCritical("FAILED")}: ${result.message || ""}`;
                this.logger.debug(msg, result);
                this._ui.userMessage(msg);
            }
            catch (err) {
                throw err;
            }
            finally {
                if (this.msgClient.isConnected()) {
                    yield this.msgClient.disconnect();
                }
            }
        });
    }
    describe(cluster) {
        return `${cluster.name} ${this._styler.dim("(" + cluster.provider + (cluster.locationName ? ", " + cluster.locationName : "") + ")")}`;
    }
    describeForList(cluster) {
        var _a, _b;
        const UTF8_HEART = "\u2665";
        if (cluster.instance) {
            let dim1 = ` (${cluster.provider}, ${cluster.locationName})`;
            let dim2 = ` (${new Date((_a = cluster.modified) !== null && _a !== void 0 ? _a : "").toLocaleDateString()}, by ${(_b = cluster.modifiedBy) !== null && _b !== void 0 ? _b : ""})`;
            return `${cluster.name} ${this._styler.dim(dim1)} ${this._styler.dim(dim2)}`;
        }
        // default to showing the name and provider if no instance
        return this.describe(cluster);
    }
}
exports.default = NocClusterDestroy;
NocClusterDestroy.description = 'Kills the physical cluster, but not the Codiac cluster definition record';
NocClusterDestroy.aliases = ["cluster:destroy"];
NocClusterDestroy.args = {
    name: core_1.Args.string({ description: 'Name of cluster to destroy' })
};
NocClusterDestroy.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    provider: core_1.Flags.string({ char: 'p', options: Object.keys(codiac_domain_1.CloudProviderEnum), description: 'REQUIRED: Code for the cloud service provider.' }),
    deleteIdentity: core_1.Flags.boolean({ char: 'i', description: 'OPTIONAL: Ensures that identity security account for the cluster shall also be deleted after the cluster itself is destroyed.', default: false }),
    partials: core_1.Flags.boolean({ char: 'a', description: "OPTIONAL: Include clusters that were never fully created." }),
    local: core_1.Flags.boolean({ char: 'l', description: "OPTIONAL: Include only clusters that reside locally on this machine." }),
    silent: core_1.Flags.boolean({
        char: 's',
        description: 'Runs the command in silent mode. Requires --name and --provider flags.',
        exclusive: ['echo', 'to-script'],
        relationships: [{ type: 'all', flags: ['provider'] }]
    }),
    echo: core_1.Flags.boolean({ char: 'e', description: 'Prints the command that would be executed, but does not execute it.' }),
    'to-script': core_1.Flags.boolean({ char: 't', description: 'Prints the command that would be executed and exits.' }),
    'take-defaults': core_1.Flags.boolean({ char: 'd', description: 'Takes all defaults for prompts.' })
};
//# sourceMappingURL=destroy.js.map