"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 type_safety_utils_1 = require("../../../uilogic/type-safety-utils");
const _ = require("lodash");
class NocClusterInit extends command_base_enterprise_1.CommandBaseEnterprise {
    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(NocClusterInit);
                    (_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.subscribe(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
                        var _b, _c, _d, _e;
                        try {
                            if (flags.silent)
                                this.__ui = new ops_1.ThrowingUserInputProvider(this.logger);
                            this._userCntx = yield this.establishTenantContext(this._userCntx);
                            let provider = (flags.provider) ? type_safety_utils_1.TypeSafetyUtils.toEnum(codiac_domain_1.CloudProviderEnum, flags.provider) : undefined;
                            let adjust = (flags.adjust != undefined) ? flags.adjust : undefined;
                            let cluster;
                            let crit = { privateOwner: (_b = this._userCntx) === null || _b === void 0 ? void 0 : _b.currentTenantCode };
                            // Ensure that the type alias matches the projection...
                            let projection = { pathsIncluded: ["id", "name", "provider", "providerSubscription", "locationName", "privateOwner", "instance", "ingressDef"], pathsExcluded: [] };
                            let readResult = yield this._codiacApi.ClusterDef.tryReadMany(crit, { projection: projection });
                            let clusterDefs = readResult.output ? readResult.output.map(c => c).filter(c => c.instance != undefined) : []; // we can only deinit clusters that have an instance
                            if (type_safety_utils_1.TypeSafetyUtils.isEnum(codiac_domain_1.CloudProviderEnum, provider)) {
                                clusterDefs = clusterDefs.filter(c => c.provider == provider);
                            }
                            let confirm = false;
                            if (readResult.error === undefined && clusterDefs.length === 0) {
                                this._ui.userMessage("No clusters exist with instances to initialize");
                            }
                            else if (flags.silent) {
                                const subx = (_c = clusterDefs.find(c => c.name == flags.name && c.provider == provider)) === null || _c === void 0 ? void 0 : _c.providerSubscription;
                                cluster = { name: flags.name, provider: (provider), providerSubscription: subx };
                            }
                            else {
                                let candidate = {};
                                if (flags.name)
                                    candidate.name = flags.name;
                                do {
                                    if (readResult.error) {
                                        // if there is a problem with the cluster record, it may prevent a good read, 
                                        // so we're going to allow the user to invoke the operation nonetheless.
                                        let allPvds = this.cspUiFactory.getAllClusterProviders(this.ioc);
                                        const csp = yield this.cspContextualizer.promptForCloudProvider(allPvds, undefined);
                                        const name = (yield this._ui.prompt("clusterName", "Enter name of the cluster to initialize:", true));
                                        const subx = (yield this._ui.prompt("clusterSubx", (csp == codiac_domain_1.CloudProviderEnum.aws ? "AccountId" : "SubscriptionId").concat(" of the cluster to deinitialize:"), true));
                                        cluster = { name: name, provider: csp, providerSubscription: subx };
                                    }
                                    else { // if (readResult.success && readResult.output && readResult.output.length > 0) {
                                        let found = (candidate.name) ? clusterDefs.find(c => c.name === candidate.name) : undefined;
                                        if (found) {
                                            cluster = found;
                                        }
                                        else {
                                            let choices = clusterDefs
                                                .map(c => { return { name: this.describe(c), value: c.name }; });
                                            const name = (yield this._ui.promptSelect("clusterName", "Select the cluster to initialize:", choices));
                                            let def = clusterDefs.find(c => c.name === name);
                                            cluster = def; // { name: name, provider: def!.provider, providerSubscription: def!.providerSubscription };
                                        }
                                    }
                                    if (cluster.ingressDef == undefined || _.isEmpty(cluster.ingressDef) || adjust == true) {
                                        // Use existing ingressIp as default for this init
                                        const existingIp = (_d = cluster.instance) === null || _d === void 0 ? void 0 : _d.ingressIp;
                                        if ((existingIp != undefined) && (((_e = cluster.ingressDef) === null || _e === void 0 ? void 0 : _e.ingressIp) == undefined)) {
                                            cluster.ingressDef = Object.assign(Object.assign({}, cluster.ingressDef), { ingressIp: existingIp });
                                        }
                                        let regCfg = this.cspUiFactory.create(cluster.provider, this.ioc);
                                        cluster.ingressDef = yield regCfg.promptForIngressSpec(cluster.ingressDef);
                                    }
                                    confirm = yield this._ui.promptConfirm("confirmInit", `Initialize the cluster: ${this._styler.hilite(this.describe(cluster))} ? `, false);
                                    if (!confirm)
                                        candidate = {}; // if cluster was set as a cmd flag, but they denied the confirm, this allows selecting a different one.
                                } while (confirm !== true);
                            }
                            if (cluster) {
                                if (confirm == true || flags.silent) {
                                    if (!flags.silent) {
                                        yield this.cspContextualizer.promptForCloudProviderCreds(this.ioc, cluster.provider, undefined, undefined, undefined, cluster.providerSubscription);
                                    }
                                    // REQUEST-RESPONSE MODE
                                    // this._ui.startSpinner(`Initializing cluster: ${this._styler.hilite(cluster.name)}`);
                                    // let resultIngress = await this.genRelayClient.Call.clusterInit({ clusterName: cluster.name });
                                    // this._ui.stopSpinner(resultIngress.success ? "SUCCESS" : "FAILED");
                                    // 
                                    // let msg = `Cluster Initialize ${resultIngress.success ? this._styler.colorGood("SUCCESS") : this._styler.colorCritical("FAILED")}: ${resultIngress.message || ""}`;
                                    // this.logger.debug(msg, resultIngress);
                                    // this._ui.userMessage(msg);
                                    // ASYNC STREAMING-STATUS MODE
                                    let result = yield this.watcher.triggerAndWatch((socketId) => this.genRelayClient.Call.clusterInit({ spec: { clusterName: cluster.name, ingressDef: cluster === null || cluster === void 0 ? void 0 : cluster.ingressDef }, socketId: socketId }) // Assertion ok - verified above
                                    );
                                    if (result.error) {
                                        let msg = `Error initializing ${cluster.provider} cluster [${cluster.name}]: ${result.message} ${result.error.message || ""}`;
                                        this.logger.error(msg, result.error);
                                        this._ui.userMessage(`${this._styler.colorCritical("ERROR!")} ${msg}`);
                                    }
                                    else if (!result.success) {
                                        let msg = `Failed without error initializing ${cluster.provider} cluster [${cluster.name}]: ${result.message}`;
                                        this.logger.notice(msg, result);
                                        this._ui.userMessage(`${this._styler.colorCritical("FAILED!")} ${msg}`);
                                    }
                                    else {
                                        let msg = `${this._styler.colorGood("SUCCESS!")} Initialized cluster [${this._styler.hilite(cluster.name)}], ${cluster.provider} subscription [${cluster.providerSubscription}].`;
                                        this.logger.notice(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();
                            resolve();
                        }
                    }));
                }
                catch (err) {
                    this.handleError(err);
                }
                finally {
                    yield this.closeConnections();
                    resolve();
                }
            }));
        });
    }
    /** Renders a user-friendly cluster description. */
    describe(cluster) {
        return `${cluster.name} ${this._styler.dim("(" + cluster.provider + (cluster.locationName ? ", " + cluster.locationName : "") + ")")}`;
    }
}
exports.default = NocClusterInit;
NocClusterInit.description = 'Post-create initialization for the cluster (installs the ingress controller service)';
NocClusterInit.aliases = ["cluster:init"];
NocClusterInit.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    name: core_1.Flags.string({ char: 'n', required: false, description: 'Name of the cluster.' }),
    provider: core_1.Flags.string({ char: 'p', options: Object.keys(codiac_domain_1.CloudProviderEnum), required: false, description: 'Code for the cloud service provider.' }),
    adjust: core_1.Flags.boolean({ required: false, description: `(Optional: defaults to false) Invoke interactive user-interface to make changes to the initialization specs.` }),
    silent: core_1.Flags.boolean({ char: 'y', dependsOn: ["name"], required: false, description: `(Optional: defaults to false) Prevents interactive user-interface and throws if interaction is needed. Requires arguments: [--name -n]` })
};
NocClusterInit.args = {
    name: core_1.Args.string({ description: 'Name of existing cluster to initialize.' })
};
//# sourceMappingURL=init.js.map