"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 CabinetCreate 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(CabinetCreate);
            //Defaults enterprise
            let partial = {};
            if (args.cabinet)
                partial.cabinet = args.cabinet;
            if (flags.environment)
                partial.environment = flags.environment;
            if (flags.cluster)
                partial.cluster = flags.cluster;
            //Overrides enterpriseCode if passed in
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            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) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.cabinet)
                throw new Error("Cabinet name must be set");
            if (!partial.environment)
                throw new Error("Environment must be set");
            if (!partial.cluster)
                throw new Error("Cluster must be set");
            // Validate cabinet name
            const cabinetNameRegex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;
            if (!cabinetNameRegex.test(partial.cabinet)) {
                throw new Error("Invalid cabinet name. It must consist of lowercase alphanumeric characters or '-', and must start and end with an alphanumeric character. Maximum length is 63 characters.");
            }
            // Matches EKS
            if (partial.cabinet.length > 63) {
                throw new Error("Cabinet name is too long. Maximum length is 63 characters.");
            }
            //validate enterprise exists
            let enterprise = rootMap.enterprises.find(e => e.name === partial.enterprise);
            if (!enterprise)
                throw new Error(`Enterprise ${partial.enterprise} not found`);
            //Validate Environment exists
            let environment = enterprise === null || enterprise === void 0 ? void 0 : enterprise.environments.find(env => env.name === partial.environment);
            if (!environment)
                throw new Error(`Environment ${partial.environment} not found in enterprise ${partial.enterprise}`);
            //Validate cluster exists & maybe default to first if not set?
            let clusters = (environment === null || environment === void 0 ? void 0 : environment.clusters) || [];
            let cluster = clusters.find(c => c.name === partial.cluster);
            if (!cluster)
                throw new Error(`Cluster ${partial.cluster} not found in environment ${partial.environment}`);
            //Validate cabinet name and not duplicate
            let cabinet = environment.cabinets.find(cab => cab.name === partial.cabinet);
            if (cabinet)
                throw new Error(`Cabinet ${partial.cabinet} already exists in environment ${partial.environment}`);
            return partial;
        });
    }
    buildCandidate_silently(partial, rootMap) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            partial = yield this.validatePartial(partial, rootMap);
            const ent = rootMap.enterprises.find(e => e.name == partial.enterprise);
            const environment = ent === null || ent === void 0 ? void 0 : ent.environments.find(e => e.name == partial.environment);
            if (environment == undefined)
                throw new Error("environment not found"); // This clause is for the ts editor; this should already have been validated.
            let hasLocalClusters = type_safety_utils_1.TypeSafetyUtils.toBoolean(environment.thisMachine);
            if (hasLocalClusters)
                partial.thisMachine = hasLocalClusters;
            return partial;
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let environment;
            let cluster;
            let cabinetName;
            let candidate;
            let confirm;
            // Wrap in a do-while loop to allow for re-entry if the user wants to re-enter any values after confirmation
            do {
                cabinetName = (_a = partial.cabinet) !== null && _a !== void 0 ? _a : (yield this._ui.prompt("cabinetName", "Cabinet name: ", true));
                [environment, cluster] = yield this.rootMapUtils.promptForEnviroCluster(rootMap, partial.enterprise, partial.environment, undefined, undefined);
                let uiCloudProvider = this.ioc.get(cloud_provider_contextualizer_1.CloudProviderContextualizer);
                yield uiCloudProvider.promptForCloudProviderCreds(this.ioc, cluster.provider, undefined, undefined, undefined, cluster.providerSubscriptionId);
                let hasLocalClusters = type_safety_utils_1.TypeSafetyUtils.toBoolean(environment.thisMachine);
                if (hasLocalClusters)
                    partial.thisMachine = hasLocalClusters;
                candidate = {
                    enterprise: partial.enterprise,
                    environment: environment.name,
                    cabinet: cabinetName,
                    cluster: cluster.name,
                    thisMachine: partial.thisMachine
                };
                // We want to validate before we show the user the full/final preview
                candidate = yield this.validatePartial(candidate, rootMap);
                // CONFIRM
                let preview = Object.assign(Object.assign({}, candidate), { cluster: { name: cluster.name, provider: cluster.provider, location: cluster.locationName } });
                this.dataAuthUtils.removeAcl(preview);
                this._ui.userMessage((0, prettify_1.prettify)(preview));
                this._ui.userMessage("You are about to create this cabinet");
                confirm = yield this._ui.promptConfirm("confirm", `Continue? (ctrl-C to cancel)`, false);
            } while (confirm !== true);
            return candidate;
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push(candidate.cabinet);
        cmd.push("--enterprise", candidate.enterprise);
        cmd.push("--environment", candidate.environment);
        cmd.push("--cluster", candidate.cluster);
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this._ui.startSpinner(`Creating new cabinet [${candidate.enterprise}/${candidate.cabinet}]...`);
            const req = { targetCabinet: candidate, targetClusterName: candidate.cluster, thisMachine: candidate.thisMachine };
            let result = yield this.genRelayClient.Call.postExecuteCabinetMaker(req);
            this._ui.stopSpinner(`${result.success ? "Success!" : "Failed."}`);
            if (result.error) {
                this.logger.error(`Error creating cabinet: ${result.message || ""}; ${result.error.message}`, result.error);
                this._ui.userMessage(`Error creating cabinet: ${result.message || ""}; ${result.error.message}`);
            }
            else if (!result.success) {
                this.logger.notice(`Cabinet creation failed without error. ${result.message}`);
                this._ui.userMessage(`Cabinet creation failed without error. ${result.message}`);
            }
            else if (result.output) {
                let cab = result.output;
                this.logger.notice(`${this._styler.colorGood("Success!")} Cabinet [${this._styler.hilite(cab.name)}] created for enterprise [${cab.enterpriseCode}]`);
                this._ui.userMessage(`${this._styler.colorGood("Success!")} Cabinet [${this._styler.hilite(cab.name)}] created for enterprise [${cab.enterpriseCode}]`);
            }
        });
    }
}
exports.default = CabinetCreate;
CabinetCreate.description = 'Initializes a cabinet for a given enterprise and environment. Returns an error if the cabinet already exists.';
CabinetCreate.aliases = ["cab:create"];
CabinetCreate.args = {
    cabinet: core_1.Args.string({ required: false, description: 'The name of the cabinet to create' })
};
//TODO: Finish me!!
CabinetCreate.examples = [
    { description: "Create a cabinet interatively.", command: "cod cabinet create" },
    { description: "Create a cabinet interatively and assemble a non-interactive command string.", command: "cod cabinet create --echo" },
    { description: "Assemble a non-interactive command string WITHOUT actually creating a cabinet (dry run).", command: "cod cabinet create --to-script" },
    { description: "Create a cabinet silently.", command: "cod cabinet create my-cab-name --enterprise main -e dev-environemt -c my-cluster --silent" },
];
CabinetCreate.flags = Object.assign(Object.assign({}, cli_common_1.commandBase.globalFlags), { help: core_1.Flags.help({ char: 'h' }), enterprise: core_1.Flags.string({ description: '(required only if more than one enterprise exists) The name of the enterprise under which to create this cabinet.' }), environment: core_1.Flags.string({ char: 'e', multiple: false, description: '(optional: defaults to that of the current project branch) The name of the environment this cabinet will be grouped under.' }), cluster: core_1.Flags.string({ char: 'c', description: '(optional: defaults to the first cluster in the environment) The name of the cluster to use for the cabinet.' }), 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