"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 cloud_provider_contextualizer_1 = require("../../uilogic/cloud-provider-contextualizer");
const config_ui_utils_1 = require("../../uilogic/config-ui-utils");
const prettify_1 = require("../../prettify");
const type_safety_utils_1 = require("../../uilogic/type-safety-utils");
class EnvironmentCreate extends command_base_exec_1.CommandBaseExec {
    bootstrap() {
        super.bootstrap();
        cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc);
    }
    captureArgs() {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(EnvironmentCreate);
            //Defaults enterprise
            let partial = {};
            if (args.name)
                partial.name = args.name;
            if (flags.enterprise) {
                partial.enterprise = flags.enterprise;
                partial.enterpriseSource = 'flag';
            }
            if (flags.cluster)
                partial.clusterDefs = flags.cluster.map(c => { return { name: c }; });
            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];
        });
    }
    validatePartial(partial, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            //validate environment name (does not already exist)
            if (!partial.name)
                throw new Error("Environment name is required.");
            if ((_a = rootMap.enterprises.find(e => e.name === partial.enterprise)) === null || _a === void 0 ? void 0 : _a.environments.find(e => e.name === partial.name)) {
                throw new Error(`An environment with the name "${partial.name}" already exists in the enterprise "${partial.enterprise}".`);
            }
            //Validate clusters selected (they exist)
            if (!partial.clusterDefs || partial.clusterDefs.length == 0)
                throw new Error("At least one cluster must be selected.");
            let invalidClusters = partial.clusterDefs.filter(c => !rootMap.clusters.find(rc => rc.name === c.name));
            if (invalidClusters.length > 0) {
                throw new Error(`The following clusters are invalid: ${(0, prettify_1.prettify)(invalidClusters.map(c => c.name))}`);
            }
            // Validate for local data
            if (partial.thisMachine == true) {
                let hasPublicClusters = Boolean(((_b = partial.clusterDefs) === null || _b === void 0 ? void 0 : _b.find(c => !type_safety_utils_1.TypeSafetyUtils.toBoolean(c.thisMachine))) != undefined);
                if (hasPublicClusters) {
                    throw new Error("You cannot attach both local and remote clusters to an environment; an environment must only support either local clusters or remote, not both.");
                }
            }
            partial.sequence = rootMap.clusters.length;
            return partial;
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let hasLocalClusters = Boolean(((_a = partial.clusterDefs) === null || _a === void 0 ? void 0 : _a.find(c => type_safety_utils_1.TypeSafetyUtils.toBoolean(c.thisMachine))) != undefined);
            if (hasLocalClusters)
                partial.thisMachine = hasLocalClusters;
            return yield this.validatePartial(partial, rootMap);
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // Prompt for Environment Name:
            let found = {};
            do {
                partial.name = (yield this._ui.prompt("name", "Environment name: ", true, partial.name));
                found = (_a = rootMap.enterprises.find(e => e.name === partial.enterprise)) === null || _a === void 0 ? void 0 : _a.environments.find(e => e.name === partial.name);
                if (found) {
                    this._ui.userMessage(`${this._styler.colorWarning("INVALID: ")} An environment with that name already exists in this enterprise.`);
                }
            } while (found !== undefined);
            // PROMPT SELECT CLUSTERS:
            //prompt for confirmation if clusters provided using flags
            if (partial.clusterDefs && partial.clusterDefs.length > 0) {
                let confirmed = yield this._ui.promptConfirm("confirm", `Selected clusters: \n${(0, prettify_1.prettify)(partial.clusterDefs.map(c => c.name))}. Continue?`);
                if (!confirmed) {
                    //Clear clusters if user does not confirm
                    partial.clusterDefs = [];
                }
                else {
                    //Validate selected clusters
                    let invalidClusters = partial.clusterDefs.filter(c => !rootMap.clusters.find(rc => rc.name === c.name));
                    if (invalidClusters.length > 0) {
                        this._ui.userMessage(`The following clusters are invalid: ${(0, prettify_1.prettify)(invalidClusters.map(c => c.name))}`);
                        //Clear clusters if invalid
                        partial.clusterDefs = [];
                    }
                }
            }
            // If no clusters provided (or was cleard out above) prompt user to select clusters
            if (!partial.clusterDefs || partial.clusterDefs.length == 0) {
                let choices = rootMap.clusters.map((c, index) => { return { name: `${c.name}  (${c.provider}, ${c.locationName})`, value: index }; });
                if (choices.length == 0)
                    throw new Error("You have no clusters defined yet. You need to create one before you can create an environment.");
                let selectedIndex = (yield this._ui.promptSelect("cluster", "Cluster to include: ", choices, true, undefined));
                let clusterNames = [rootMap.clusters[selectedIndex].name];
                partial.clusterDefs = yield this._codiacApi.ClusterDef.readMany({ name: { $in: clusterNames } }, { throwNotFound: true });
            }
            let hasLocalClusters = Boolean(((_b = partial.clusterDefs) === null || _b === void 0 ? void 0 : _b.find(c => type_safety_utils_1.TypeSafetyUtils.toBoolean(c.thisMachine))) != undefined);
            if (hasLocalClusters)
                partial.thisMachine = hasLocalClusters;
            return yield this.validatePartial(partial, rootMap);
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push(candidate.name);
        cmd.push("--enterprise", candidate.enterprise);
        cmd.push("--silent");
        return cmd;
    }
    candidateToFinalCandidate(candidate) {
        //Unit testable conversion logic (kept seprate from "executeTask" for testing)
        let final = Object.assign({ code: candidate.name, enterpriseCode: candidate.enterprise, subscription: "", sequence: candidate.sequence, clusterDefs: candidate.clusterDefs, cabinets: [] }, this.createAuditable());
        if (candidate.thisMachine == true) {
            final.thisMachine = type_safety_utils_1.TypeSafetyUtils.toBoolean(candidate.thisMachine);
        }
        return final;
    }
    executeTask(candidate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // Assemble and write
            let final_candidate = this.candidateToFinalCandidate(candidate);
            this._ui.startSpinner(`Creating new environment [${final_candidate.enterpriseCode}/${final_candidate.code}]...`);
            // let result = await relayClient.cabinetCreate(<CabinetScope>{ enterprise: enterpriseCode, cabinet: cabinetName, environment: environment });
            let result = yield this._codiacApi.Environment.tryCreate(final_candidate);
            this._ui.stopSpinner("");
            if (result.error) {
                this.logger.error(`Error creating environment: ${result.message || ""}; ${result.error.message}`, result.error);
                this._ui.userMessage(`Error creating environment: ${result.message || ""}; ${result.error.message}`);
            }
            else if (!result.success) {
                this.logger.notice(`Environment creation failed without error.  ${result.message}`);
                this._ui.userMessage(`Environment creation failed without error.  ${result.message}`);
            }
            else if (result.output) {
                let saved = result.output;
                this.logger.notice(`${this._styler.colorGood("Success!")} Environment [${this._styler.hilite(saved.code)}] created for enterprise [${final_candidate.enterpriseCode}]`);
                this._ui.userMessage(`${this._styler.colorGood("Success!")} Environment [${this._styler.hilite(saved.code)}] created for enterprise [${final_candidate.enterpriseCode}]`);
            }
        });
    }
}
exports.default = EnvironmentCreate;
EnvironmentCreate.description = 'Create a new environment for a given enterprise. Returns an error if the environment already exists.';
EnvironmentCreate.aliases = ["enviro:create"];
EnvironmentCreate.args = {
    name: core_1.Args.string({ required: false, description: 'The name of the environment to create' })
};
EnvironmentCreate.examples = [
    { description: "Create a cabinet interativley.", command: "cod environment create" },
    { description: "Create a cabinet with cluster selected.", command: "cod environment create dev --cluster my-cluster-1" },
    { description: "Create a cabinet with multiple clusters selected.", command: "cod environment create dev --cluster my-cluster-1 --cluster my-cluster-2" },
    { description: "Create a cabinet silently.", command: "cod environment create dev --enterprise main --cluster my-cluster-1 --cluster my-cluster-2 --silent" },
];
EnvironmentCreate.flags = Object.assign(Object.assign({ cluster: core_1.Flags.string({ char: 'c', description: '(Required in silent mode) The cluster/s the environment will include.', multiple: true, required: false }), enterprise: core_1.Flags.string({ char: 'e', required: false, description: '(required only if more than one enterprise exists) The enterprise in which to create the environment.' }) }, cli_common_1.commandBase.globalFlags), { help: core_1.Flags.help({ char: 'h' }), 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.' }), 
    //Not sure what to do with this one yet
    "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)." }) });
//# sourceMappingURL=create.js.map