"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 command_base_enterprise_1 = require("../../../command-base-enterprise");
const ops_1 = require("../../../ops");
const _ = require("lodash");
class NocClusterGrant extends command_base_enterprise_1.CommandBaseEnterprise {
    constructor() {
        super(...arguments);
        this.clusterDefs = [];
    }
    run() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _a;
                try {
                    this.bootstrap();
                    const { args, flags } = yield this.parse(NocClusterGrant);
                    (_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.subscribe((ready) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                        var _b;
                        try {
                            if (flags.silent)
                                this.__ui = new ops_1.ThrowingUserInputProvider(this.logger);
                            this._userCntx = yield this.establishTenantContext(this._userCntx);
                            let grant;
                            this.clusterDefs = yield this.loadClusters();
                            if (this.clusterDefs.length === 0) {
                                this._ui.userMessage("No clusters found");
                            }
                            else if (flags.silent) {
                                // Build candidate silently
                                if (flags.user == undefined || flags.user.length === 0)
                                    throw new Error(`No user provided.`);
                                if (_.isEmpty(flags.cluster))
                                    throw new Error(`No cluster provided.`);
                                let found = this.clusterDefs.find(c => c.name === flags.cluster);
                                if (!found)
                                    throw new Error(`Given cluster does not exist in this tenant.`);
                                grant = { cluster: found, user: flags.user };
                            }
                            else {
                                // Build candidate interactively
                                let candidate = {};
                                if (flags.cluster) {
                                    let found = this.clusterDefs.find(c => c.name === flags.cluster);
                                    if (found)
                                        candidate.cluster = found;
                                }
                                if (flags.user && !_.isEmpty(flags.user))
                                    candidate.user = flags.user;
                                let confirm = false;
                                do {
                                    candidate.cluster = yield this.promptForCluster((_b = candidate.cluster) === null || _b === void 0 ? void 0 : _b.name);
                                    candidate.user = yield this.promptForUser(candidate.user);
                                    this._ui.userMessage(`Granting cluster access on [${this._styler.hilite(candidate.cluster.name)}] to user [${this._styler.hilite(candidate.user)}]`);
                                    confirm = yield this._ui.promptConfirm("confirmGrant", `Continue? (Ctrl-C to cancel)`, false);
                                } while (confirm !== true);
                                grant = candidate;
                            }
                            if (grant) {
                                if (!flags.silent) {
                                    yield this.cspContextualizer.promptForCloudProviderCreds(this.ioc, grant.cluster.provider, undefined, undefined, undefined, grant.cluster.providerSubscription);
                                }
                                this._ui.startSpinner(`Granting access...`);
                                let result = yield this.genRelayClient.Call.grantClusterAccess({ clusterName: grant.cluster.name, users: [grant.user] });
                                this._ui.stopSpinner(result.success ? "SUCCESS" : "FAILED");
                                let msg = `Access grant ${result.success ? this._styler.colorGood("SUCCEEDED") : this._styler.colorCritical("FAILED")}: ${result.message || ""}`;
                                this.logger.debug(msg, result);
                                this._ui.userMessage(msg);
                            }
                            else {
                                this._ui.userMessage("Operation cancelled.  No work was done.");
                            }
                        }
                        catch (err) {
                            this.handleError(err);
                        }
                        finally {
                            yield this.closeConnections();
                            return;
                        }
                    }));
                }
                catch (err) {
                    this.handleError(err);
                }
                finally {
                    yield this.closeConnections();
                    return;
                }
            }));
        });
    }
    /** Renders a user-friendly cluster description. */
    describe(cluster) {
        return `${cluster.name} ${this._styler.dim("(" + cluster.provider + (cluster.locationName ? ", " + cluster.locationName : "") + ")")}`;
    }
    /** Retrieve the list of available clusters for the current tenant. */
    loadClusters(csp) {
        var _a, _b, _c, _d;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let crit = { privateOwner: (_a = this._userCntx) === null || _a === void 0 ? void 0 : _a.currentTenantCode };
                let projection = { pathsIncluded: ["id", "name", "provider", "locationName", "privateOwner", "instance"], pathsExcluded: [] };
                let readResult = yield this._codiacApi.ClusterDef.tryReadMany(crit, { projection: projection });
                let clusterDefs = (_b = readResult.output) !== null && _b !== void 0 ? _b : []; // we can only deinit clusters that have an instance
                if (csp && Object.keys(codiac_domain_1.CloudProviderEnum).indexOf(csp) >= 0) {
                    clusterDefs = clusterDefs.filter(c => c.provider == csp);
                }
                clusterDefs = clusterDefs.filter(c => c.instance != undefined);
                clusterDefs = _.orderBy(clusterDefs, c => c.name);
                return clusterDefs;
            }
            catch (err) {
                throw new Error(`Error loading clusters: ${(_c = err.name) !== null && _c !== void 0 ? _c : ""} ${(_d = err.message) !== null && _d !== void 0 ? _d : ""}`);
            }
        });
    }
    /** Returns the name of the selected cluster.
    */
    promptForCluster(defaultValue) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let output;
            let keep = false;
            if (defaultValue && this.clusterDefs.find(c => c.name === defaultValue)) {
                keep = yield this._ui.promptConfirm("clusterNameConfirm", `Target Cluster: [${this._styler.hilite(defaultValue)}]`, true);
            }
            if (keep === true) {
                output = this.clusterDefs.find(c => c.name === defaultValue);
            }
            else {
                let choices = this.clusterDefs
                    .map(c => { return { name: this.describe(c), value: c.name }; });
                let selectedName = (yield this._ui.promptSelect("clusterName", "Select the target cluster:", choices));
                output = this.clusterDefs.find(c => c.name === selectedName);
            }
            return output;
        });
    }
    promptForUser(defaultValue) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let output;
            let keep = false;
            if (defaultValue) {
                keep = yield this._ui.promptConfirm("usernameConfirm", `AWS username: [${this._styler.hilite(defaultValue)}]`, true);
            }
            if (defaultValue != undefined && keep === true) {
                output = defaultValue;
            }
            else {
                output = (yield this._ui.prompt("username", "AWS username (email): ", true, defaultValue));
            }
            return output;
        });
    }
}
exports.default = NocClusterGrant;
NocClusterGrant.description = '(AWS Only) Provides cluster access to the given user.';
NocClusterGrant.aliases = ["cluster:grant"];
NocClusterGrant.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    cluster: core_1.Flags.string({ char: 'c', required: false, description: 'Name of the cluster.' }),
    // provider: Flags.custom({ char: 'p', options: Object.keys(CloudProviderEnum), required: false, description: 'Code for the cloud service provider.' }),
    user: core_1.Flags.string({ char: 'u', multiple: false, required: false, description: 'AWS usernames (as email) to add.' }),
    silent: core_1.Flags.boolean({ char: 'y', dependsOn: ["cluster", "user"], required: false, description: `(Optional: defaults to false) Prevents confirmations of user-values.` })
};
NocClusterGrant.args = {
    name: core_1.Args.string({ description: 'Proposed name of the cluster' })
};
//# sourceMappingURL=grant.js.map