"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");
const config_ui_utils_1 = require("../../../uilogic/config-ui-utils");
const type_safety_utils_1 = require("../../../uilogic/type-safety-utils");
class EnvironmentClusterAttach extends command_base_exec_1.CommandBaseExec {
    captureArgs() {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(EnvironmentClusterAttach);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if (flags.environment)
                partial.environmentName = flags.environment;
            if (flags.cluster)
                partial.cluster = flags.cluster;
            // ---------------------------------------------------------------
            // TODO: move everything from here down into the base class
            // ---------------------------------------------------------------
            const interactionMode = (this.pipedInput) ? config_ui_utils_1.InteractionModes.silent : (_b = (_a = undefined !== null && undefined !== void 0 ? undefined : (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 = flags['take-defaults'];
            return [partial, interactionMode, takeDefaults];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (partial.environmentName == undefined || _.isEmpty(partial.environmentName))
                throw new Error("Missing environment");
            if (partial.cluster == undefined || _.isEmpty(partial.cluster))
                throw new Error("Missing cluster");
            let ent = rootMap.enterprises.find(e => e.name == partial.enterprise);
            if (!ent)
                throw new Error("Enterprise not found."); // <-- todo: move this up to the base class and pass in the enterprise object.
            let env = ent.environments.find(e => e.name == partial.environmentName);
            if (env == undefined)
                throw new Error("Environment not found.");
            partial.environment = env;
            let existing = rootMap.clusters.find(c => c.name == partial.cluster);
            if (existing == undefined)
                throw new Error("Cluster not found.");
            let attached = (_a = env.clusters) === null || _a === void 0 ? void 0 : _a.find(c => c.name == partial.cluster);
            if (attached != undefined) {
                this._ui.userMessage("Cluster is already attached to the given environment. No work to do.");
                this.exit(0);
                return;
            }
            let candidate = {
                enterprise: partial.enterprise,
                environmentName: partial.environmentName,
                environment: partial.environment,
                cluster: partial.cluster
            };
            return candidate;
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a, _b, _c, _d;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // Validate
            partial = this.rootMapUtils.validateEnviro(partial, rootMap);
            partial = this.rootMapUtils.validateCluster(partial, rootMap);
            if (partial.cluster && partial.environment) {
                let attached = (_a = partial.environment.clusters) === null || _a === void 0 ? void 0 : _a.find(c => c.name == partial.cluster);
                if (attached != undefined) {
                    this._ui.userMessage("Cluster is already attached to the given environment. No work to do.");
                    this.exit(0);
                    return;
                }
            }
            // Need to select environment and/or cluster
            if (partial.cluster == undefined || partial.environment == undefined || partial.environmentName == undefined) {
                // SELECT ENVIRO
                if (partial.environment == undefined || partial.environmentName == undefined) {
                    partial.environment = yield this.rootMapUtils.promptForEnviro(rootMap, partial.enterprise, partial.environmentName);
                    partial.environmentName = partial.environment.name;
                }
                // SELECT CLUSTER
                if (partial.cluster && partial.environment) {
                    let attached = (_b = partial.environment.clusters) === null || _b === void 0 ? void 0 : _b.find(c => c.name == partial.cluster);
                    if (attached != undefined) {
                        this._ui.userMessage("Cluster is already attached to the selected environment. No work to do.");
                        this.exit(0);
                        return;
                    }
                }
                if (partial.cluster == undefined) {
                    const envIsLocal = type_safety_utils_1.TypeSafetyUtils.toBoolean(partial.environment.thisMachine);
                    let alreadies = (_d = (_c = partial.environment.clusters) === null || _c === void 0 ? void 0 : _c.map(c => c.name)) !== null && _d !== void 0 ? _d : [];
                    let availables = rootMap.clusters.filter(c => !alreadies.includes(c.name))
                        // filter to match local-vs-remote
                        .filter(c => type_safety_utils_1.TypeSafetyUtils.toBoolean(c.thisMachine) == envIsLocal);
                    if (availables.length == 0) {
                        this._ui.userMessage("All ".concat(envIsLocal ? "local" : "remote", " clusters are already attached to the selected environment. No work to do."));
                        this.exit(0);
                        return;
                    }
                    let choices = availables
                        .map(c => ({ name: c.name, value: c.name }));
                    partial.cluster = (yield this._ui.promptSelect("cluster", "Attach Cluster: ", choices, false, false));
                }
            }
            this.rootMapUtils.validateLocalVsRemoteCluster(partial, rootMap);
            let candidate = {
                enterprise: partial.enterprise,
                environmentName: partial.environmentName,
                environment: partial.environment,
                cluster: partial.cluster
            };
            return candidate;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("--enterprise", candidate.enterprise);
        cmd.push("--environment", candidate.environmentName);
        cmd.push("--cluster", candidate.cluster);
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const req = {
                environmentId: candidate.environment.id,
                cluster: candidate.cluster,
                thisMachine: candidate.environment.thisMachine
            };
            let result = yield this._codiacApi.Call.EnvironmentClusterAttach(req);
            if (result.error)
                throw result.error;
            if (result.success) {
                this._ui.userMessage(this._styler.colorGood("Success! ").concat((_a = result.message) !== null && _a !== void 0 ? _a : "Attached cluster to environment."));
            }
            else {
                this._ui.userMessage((_b = result.message) !== null && _b !== void 0 ? _b : "Operation failed without error (Check log for details).");
            }
        });
    }
    buildEnviroListForText(flatList) {
        try {
            let listForText = flatList.map(env => {
                let clusterDesc = this.buildEnviroClusterDesc(env.clusters);
                return `${env.enterprise}/${this._styler.hilite(env.name)}${this._styler.dim(clusterDesc)}`;
            });
            return listForText;
        }
        catch (err) {
            throw err;
        }
    }
    buildEnviroClusterDesc(clusters) {
        try {
            let clusterDesc = "";
            if (clusters.length > 0) {
                if (clusters.length === 1) {
                    // Only 1, show provider and location
                    clusterDesc = ` ${clusters[0].name} (${clusters[0].provider}, ${clusters[0].locationName})`;
                }
                else {
                    // Many, list providers of clusters
                    let byProvider = _.groupBy(clusters, c => c.provider);
                    let delim = "";
                    for (let provider in byProvider) {
                        let qty = byProvider[provider].length;
                        clusterDesc = clusterDesc.concat(delim, `${qty} ${provider}`);
                        delim = ", ";
                    }
                    if (clusterDesc == "")
                        clusterDesc = ` (${clusterDesc})`;
                }
            }
            return clusterDesc;
        }
        catch (err) {
            throw err;
        }
    }
    buildEnviroTree(rootMap) {
        var _a;
        let tree = [];
        for (let ent of rootMap.enterprises) {
            let entBranch = { text: `${ent.name} enterprise:` };
            for (let env of _.sortBy(ent.environments, e => e.sequence, e => e.name)) {
                let clusterDesc = this.buildEnviroClusterDesc((_a = env.clusters) !== null && _a !== void 0 ? _a : []);
                let envBranch = {
                    text: `${this._styler.hilite(env.name)}${this._styler.dim(clusterDesc)} `
                };
                if (entBranch.children === undefined)
                    entBranch.children = [];
                entBranch.children.push(envBranch);
            }
            tree.push(entBranch);
        }
        return tree;
    }
    FlattenEnviros(rootMap) {
        var _a;
        let flattened = [];
        for (let ent of rootMap.enterprises) {
            for (let env of _.sortBy(ent.environments, e => e.sequence, e => e.name)) {
                flattened.push({
                    name: env.name,
                    sequence: env.sequence,
                    enterprise: ent.name,
                    clusters: (_a = env.clusters) !== null && _a !== void 0 ? _a : []
                });
            }
        }
        return flattened;
    }
}
exports.default = EnvironmentClusterAttach;
EnvironmentClusterAttach.description = 'Includes the given cluster within the given environment.  DOES NOT modify any infrastructure; only creates an association within Codiac.';
EnvironmentClusterAttach.aliases = ["enviro:cluster:attach"];
EnvironmentClusterAttach.flags = {
    enterprise: core_1.Flags.string({ char: 'e', description: 'The name of the enterprise in which the environment resides. NOTE: You can leave this blank if there is only one.' }),
    environment: core_1.Flags.string({ char: 'n', required: false, description: 'Name of the environment being modified.' }),
    cluster: core_1.Flags.string({ char: 'c', required: false, description: 'Name of the cluster.' }),
    // TODO: Move these into the base class
    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.' }),
    "take-defaults": core_1.Flags.boolean({ exclusive: ["silent"], description: "Setting this to true prevents prompting for confirmation on parameters that were passed in or were automatically set to default values (Irrelevant in --silent mode).  This behavior does NOT apply to scenarios that the command needs to override invalid user input; such cases will always prompt for confirmation.  eg: when no argument was provided for file or type, and only one exists, the system will render the autoselected file unless this flag is set." })
};
EnvironmentClusterAttach.args = {};
//# sourceMappingURL=attach.js.map