"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 prettify_1 = require("../../prettify");
const type_safety_utils_1 = require("../../uilogic/type-safety-utils");
class CabinetDefine extends command_base_exec_1.CommandBaseExec {
    constructor() {
        super(...arguments);
        this.infrxAliases = undefined;
    }
    bootstrap() {
        super.bootstrap();
        cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc);
    }
    captureArgs() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(CabinetDefine);
            let partial = {};
            let explicit = {};
            if (args.cabinet) {
                partial.cabinet = args.cabinet;
                explicit.cabinet = args.cabinet;
            }
            if (flags.environment) {
                partial.environment = flags.environment;
                explicit.environment = flags.environment;
            }
            if (flags.cluster) {
                partial.cluster = flags.cluster;
                explicit.cluster = flags.cluster;
            }
            if (flags.enterprise) {
                partial.enterprise = flags.enterprise;
                explicit.enterprise = flags.enterprise;
            }
            const takeDefaults = (_a = flags['take-defaults']) !== null && _a !== void 0 ? _a : false;
            return [partial, takeDefaults, explicit];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!partial.cabinet)
                throw new Error("Cabinet name must be provided.");
            if (!partial.environment)
                throw new Error("Environment must be provided.");
            if (!partial.cluster)
                throw new Error("Cluster must be provided.");
            const cabinetNameRegex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;
            if (!cabinetNameRegex.test(partial.cabinet))
                throw new Error("Invalid cabinet name. Must be lowercase alphanumeric or '-', start and end with alphanumeric.");
            if (partial.cabinet.length > 63)
                throw new Error("Cabinet name exceeds maximum length of 63 characters.");
            const enterprise = rootMap.enterprises.find(e => e.name === partial.enterprise);
            if (!enterprise)
                throw new Error(`Enterprise [${partial.enterprise}] not found.`);
            const environment = enterprise.environments.find(e => e.name === partial.environment);
            if (!environment)
                throw new Error(`Environment [${partial.environment}] not found in enterprise [${partial.enterprise}].`);
            if (!((_a = environment.clusters) === null || _a === void 0 ? void 0 : _a.find(c => c.name === partial.cluster)))
                throw new Error(`Cluster [${partial.cluster}] not found in environment [${partial.environment}].`);
            if ((_b = environment.cabinets) === null || _b === void 0 ? void 0 : _b.find(c => c.name === partial.cabinet))
                throw new Error(`Cabinet [${partial.cabinet}] already exists in environment [${partial.environment}].`);
            const env = enterprise.environments.find(e => e.name === partial.environment);
            if (type_safety_utils_1.TypeSafetyUtils.toBoolean(env.thisMachine))
                partial.thisMachine = env.thisMachine;
            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;
            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);
                const 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,
                };
                candidate = yield this.buildCandidate_silently(candidate, rootMap);
                const preview = Object.assign({}, candidate);
                this.dataAuthUtils.removeAcl(preview);
                this._ui.userMessage((0, prettify_1.prettify)(preview));
                this._ui.userMessage("You are about to define this cabinet (no k8s provisioning will occur).");
                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) {
        var _a, _b, _c, _d;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this._ui.startSpinner(`Defining cabinet [${candidate.enterprise}/${candidate.cabinet}]...`);
            const req = { targetCabinet: candidate, targetClusterName: candidate.cluster };
            const result = yield this.genRelayClient.Call.cabinetDefine(req);
            this._ui.stopSpinner(result.success ? "Done." : "Failed.");
            if (result.error) {
                this.logger.error(`Error defining cabinet: ${(_a = result.message) !== null && _a !== void 0 ? _a : ""}; ${result.error.message}`, result.error);
                this._ui.userMessage(`Error defining cabinet: ${(_b = result.message) !== null && _b !== void 0 ? _b : ""}; ${result.error.message}`);
            }
            else if (!result.success) {
                this.logger.notice(`Cabinet definition failed. ${(_c = result.message) !== null && _c !== void 0 ? _c : ""}`);
                this._ui.userMessage(`Cabinet definition failed. ${(_d = result.message) !== null && _d !== void 0 ? _d : ""}`);
            }
            else if (result.output) {
                const cab = result.output;
                this._ui.userMessage(`${this._styler.colorGood("Done!")} Cabinet [${this._styler.hilite(cab.name)}] defined for enterprise [${cab.enterpriseCode}] — run ${this._styler.hilite("cabinet restore")} to provision it.`);
            }
        });
    }
}
exports.default = CabinetDefine;
CabinetDefine.description = 'Records the cabinet metadata without provisioning any k8s infrastructure. Use when the target cluster has no physical instance yet, or to stage a cabinet definition ahead of provisioning.';
CabinetDefine.aliases = ["cab:define"];
CabinetDefine.args = {
    cabinet: core_1.Args.string({ required: false, description: 'The name of the cabinet to define.' })
};
CabinetDefine.examples = [
    { description: "Define a cabinet interactively.", command: "<%= config.bin %> <%= command.id %>" },
    { description: "Define a cabinet interactively and assemble a non-interactive command string.", command: "<%= config.bin %> <%= command.id %> --echo" },
    { description: "Assemble a non-interactive command string without defining (dry run).", command: "<%= config.bin %> <%= command.id %> --to-script" },
    { description: "Define a cabinet silently (scripted).", command: "<%= config.bin %> <%= command.id %> my-cab --enterprise main --environment dev-environment --cluster my-cluster --silent" },
];
CabinetDefine.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 enterprise under which to define the cabinet.' }), environment: core_1.Flags.string({ char: 'e', multiple: false, description: 'The environment this cabinet belongs to.' }), cluster: core_1.Flags.string({ char: 'c', description: 'The cluster to assign this cabinet to. Defaults to the only cluster in the environment when there is exactly one.' }), silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Non-interactive mode; executes without prompts and fails on any missing or invalid arguments.' }), echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Renders the equivalent non-interactive command before executing.' }), "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Renders the equivalent non-interactive command without executing it.' }), "take-defaults": core_1.Flags.boolean({ exclusive: ["silent"], description: "Accepts default values without confirmation prompts (irrelevant in --silent mode)." }) });
//# sourceMappingURL=define.js.map