"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CommandBaseEnterprise = void 0;
const tslib_1 = require("tslib");
require("reflect-metadata");
const security_1 = require("@codiac.io/codiac-common/security");
const codiac_relay_contracts_1 = require("@codiac.io/codiac-relay-contracts");
const codiac_ops_common_1 = require("@codiac.io/codiac-ops-common");
const relay_container_1 = require("./relay/relay-container");
const codiac_api_1 = require("./apis/codiac-api");
const codiac_relay_1 = require("./apis/codiac-relay");
const cli_common_1 = require("./cli-common");
const enterprise_contextualizer_1 = require("./uilogic/enterprise-contextualizer");
const environment_contextualizer_1 = require("./uilogic/environment-contextualizer");
const uilogic_1 = require("./uilogic");
const ops_1 = require("./ops");
const data_1 = require("./ops/data");
const argument_manager_1 = require("./cli-common/argument-manager");
const user_context_loader_1 = require("./user-context-loader");
const api_user_creds_1 = require("./apis/codiac-api/common/api-user-creds");
const cloud_provider_contextualizer_1 = require("./uilogic/cloud-provider-contextualizer");
const lrp_watcher_predef_1 = require("./uilogic/lrp-watcher-predef");
const rootmap_ui_utils_1 = require("./uilogic/rootmap-ui-utils");
const INTERFACES_CLI_1 = require("./ops/INTERFACES_CLI");
const operators_1 = require("rxjs/operators");
const codiac_messaging_1 = require("@codiac.io/codiac-messaging");
const config_ui_utils_1 = require("./uilogic/config-ui-utils");
const type_safety_utils_1 = require("./uilogic/type-safety-utils");
const bootstrapper_for_enterprise_commands_1 = require("./bootstrapper-for-enterprise-commands");
const codiac_messaging_2 = require("@codiac.io/codiac-messaging");
const bootstrapper_for_api_clients_1 = require("./bootstrapper-for-api-clients");
const entities_1 = require("./ops/entities");
const rxjs_1 = require("rxjs");
const operators_2 = require("rxjs/operators");
/** Ensures tenant context and k8s context.
 *  For use with commands that operate on enterprise records or on an existing cluster.
 */
class CommandBaseEnterprise extends cli_common_1.commandBase {
    constructor() {
        // constructor(argv: string[], config: Config, requiresProjectScope?: boolean) {
        //   super(argv, config, requiresProjectScope);
        // }
        super(...arguments);
        // protected loadClusterSpecSub: Subject<temp.Cluster> = new Subject();
        // public get loadClusterSpec$(): Observable<temp.Cluster> {
        //   return this.loadClusterSpecSub.asObservable();
        // }
        // protected acquireK8sContextSub: Subject<k8s.KubeConfig> = new Subject();
        // public get acquireK8sContext$(): Observable<k8s.KubeConfig> {
        //   return this.acquireK8sContextSub.asObservable();
        // }
        // protected _ui: IUserInputProvider;
        // /** Assembles the full specification for the operation that is to be performed on the cluster.  */
        // protected abstract async loadOperationInput( userCntx: UserContext, assetCntx: AssetContext): Promise<TOperationInput>;
        // /** Performs the actual intended work within the cluster. */
        // protected abstract async executeMainOperation(input: TOperationInput): Promise<void>;
        /** Requires the current user to be an adminstrator in order to execute this command. */
        this.adminOnly = false;
        /** Flag set by nats clients on create
         * to prevent the need for this class to always instantiate them
         * just to check for open connections.
         * (see implementation in `CloseConnections()`) */
        this.hasConnectedYet = false;
    }
    run() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this.bootstrap();
            yield this.readStdin();
            (_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.pipe((0, operators_2.tap)((ready) => this.logger.trace(`ready$ emitted: ${ready}`)), (0, operators_2.concatMap)((ready) => (0, rxjs_1.from)((() => tslib_1.__awaiter(this, void 0, void 0, function* () {
                this.logger.trace(`Relay container ready: ${ready}`);
                // 0. SET DEFAULTS
                yield this.runAsync();
                // await this.testPromise(true, this.logger);
                return ready; // Return ready value if no error
            }))())), (0, operators_2.tap)((ready) => {
                // Send user messages based on ready state
                if (ready) {
                    this.logger.trace("Relay container is ready");
                }
                else {
                    this.logger.trace("Relay container not ready");
                }
            }), (0, operators_2.take)(1), // Complete after first valid emission
            (0, operators_2.catchError)((err) => {
                this.logger.error("Error occured:", err);
                this.handleError(err);
                return (0, rxjs_1.of)(false);
            }), (0, operators_2.finalize)(() => {
                this.logger.trace("start finalization");
                this.closeConnections().then(() => {
                    this.logger.trace("finalized - connections closed");
                }).catch((err) => {
                    this.logger.error(`Error during dispose: ${err.message}`);
                }).finally(() => {
                    this.logger.trace("destroy stdin pipe");
                    if (!process.stdin.destroyed)
                        process.stdin.destroy();
                });
            })).subscribe(_ => {
                this.logger.debug("Subscribing to the relay");
                // process.exit(err.code ?? 1);
            });
        });
    }
    ;
    runAsync() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            this.logger.notice("runAsync override");
        });
    }
    bootstrap() {
        bootstrapper_for_enterprise_commands_1.BootstrapperForEnterpriseCommands.bootstrap(this.ioc, this);
    }
    /** Teardown method.  Logs errors but does not throw.
     * This is an exit method, to prevent any unresolved promises
     * from open messaging connections and listeners. */
    closeConnections() {
        var _a, _b, _c, _d, _e, _f;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // In most cases this clause will fire BEFORE user interfaces with command,
            // because most commands are run async.  
            // In these cases, creating a streaming connector can cause a visible delay.
            // so to avoid this unnecessary delay, we need do a pre-check without instantiating first.
            if (this.hasConnectedYet == true) {
                // Close out Nats client...
                if (codiac_messaging_1.utils.isBoundDefault(this.ioc, codiac_messaging_2.StreamingConstants.IStreamingConnector)) {
                    const connector = this.ioc.get(codiac_messaging_2.StreamingConstants.IStreamingConnector);
                    if (connector.areAnyConnected()) {
                        try {
                            yield connector.disconnectAll();
                        }
                        catch (err) {
                            this.logger.error("Error closing codiac api connections: ".concat((_c = (_b = (_a = err.message) !== null && _a !== void 0 ? _a : err.name) !== null && _b !== void 0 ? _b : err.stack) !== null && _c !== void 0 ? _c : "no details available."));
                        }
                    }
                }
                // // Close out Nats client...
                // if (CodiacNatsClient.areAnyConnected()) {
                //   try {
                //     await CodiacNatsClient.disconnectAll();
                //   } catch (err) {
                //     this.logger.error("Error closing codiac api connections: ".concat(err.message ?? err.name ?? err.stack ?? "no details available."));
                //   }
                // }
                // Close out Nats client...
                const connectorForRelay = this.ioc.getNamed(codiac_messaging_2.StreamingConstants.IStreamingConnector, bootstrapper_for_api_clients_1.BootstrapperForApiClients.RELAY_NATS_INSTANCE);
                if (connectorForRelay.areAnyConnected()) {
                    try {
                        yield connectorForRelay.disconnectAll();
                    }
                    catch (err) {
                        this.logger.error("Error closing relay connections: ".concat((_f = (_e = (_d = err.message) !== null && _d !== void 0 ? _d : err.name) !== null && _e !== void 0 ? _e : err.stack) !== null && _f !== void 0 ? _f : "no details available."));
                    }
                }
            }
            return;
        });
    }
    ;
    exit(exitCode) {
        this.closeConnections()
            .finally(() => {
            super.exit(exitCode);
        });
    }
    /* ==================================================================================================
     *     _                       _                     _
     *    | |                     | |                   | |
     *    | |     __ _ _____   _  | |     ___   __ _  __| |___
     *    | |    / _` |_  / | | | | |    / _ \ / _` |/ _` / __|
     *    | |___| (_| |/ /| |_| | | |___| (_) | (_| | (_| \__ \
     *    \_____/\__,_/___|\__, | \_____/\___/ \__,_|\__,_|___/
     *                      __/ |
     *                     |___/
     * ================================================================================================== */
    get dataAuthUtils() {
        if (this.__dataAuthUtils === undefined) {
            this.__dataAuthUtils = new security_1.DataAuthUtils();
        }
        return this.__dataAuthUtils;
    }
    get dataAuthProvider() {
        var _a, _b;
        if (this.__dataAuthProvider === undefined) {
            // HACK: we need a _userCntx.tenantUser instead of assembling one like this...
            let tenantUser = {
                login: this._userCntx.userName,
                tenantCode: this._userCntx.currentTenantCode,
                roles: (_b = (_a = this._userCntx.roles) === null || _a === void 0 ? void 0 : _a.map(r => ({ name: r }))) !== null && _b !== void 0 ? _b : []
            };
            this.__dataAuthProvider = new security_1.DataAuthProvider(tenantUser); // any cast bc we only need the roles here.
        }
        return this.__dataAuthProvider;
    }
    /** Prompts for Cloud Provider credentials. */
    get cspContextualizer() {
        if (this.__cspContextualizer === undefined) {
            cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc); // Consider moving this to this.bootstrap().  Leaving it here is only saving us microseconds off the class' bootstrap method.
            this.__cspContextualizer = this.ioc.get(cloud_provider_contextualizer_1.CloudProviderContextualizer);
        }
        return this.__cspContextualizer;
    }
    // let cspContextualizer = this.cspContextualizer; // hack: gotta trigger the bootstrap before we pull from factory.
    // let factory = new ClusterConfiguratorFactory(); //this._codiacApi, this._ui, this.logger);
    /** Prompts for Cloud Provider credentials. */
    get cspUiFactory() {
        if (this.__cspConfiguratorfactory === undefined) {
            // Consider moving these bootstrap calls to this.bootstrap().  Leaving them here is only saving us microseconds off the class' bootstrap method.
            cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc); // (idempotent) this is a dependency of the configurators
            uilogic_1.ClusterConfiguratorFactory.bootstrap(this.ioc, this);
            this.__cspConfiguratorfactory = this.ioc.get(uilogic_1.ClusterConfiguratorFactory);
        }
        return this.__cspConfiguratorfactory;
    }
    /** Resource types supported by the SDK,
     * implemented by the currently registered Csp Adapters. */
    get cspSupportMap() {
        if (this.__cspSupportMap === undefined) {
            this.__cspSupportMap = this.ioc.get(uilogic_1.INTERFACES_CLI_ENTERPRISE.CspSupportMap);
        }
        return this.__cspSupportMap;
    }
    set _userCntx(cntx) {
        this.__userCntx = cntx;
    }
    get _userCntx() {
        var _a, _b;
        if (this.__userCntx === undefined) {
            let userLoader = new user_context_loader_1.UserContextLoader(this.cliEnviro, this.logger);
            this.__userCntx = (_b = userLoader.loadUserContext((_a = this._projCfg) === null || _a === void 0 ? void 0 : _a.tenantCode)) !== null && _b !== void 0 ? _b : new codiac_relay_contracts_1.UserContext();
        }
        return this.__userCntx;
    }
    // COMMENTED OUT BC: handled entirely within the enterprise bootstrapper. 
    // /** The system of record for this url.  
    //  * 
    //  * NOTE: This property is called by the NatsClient bootstrapper. */
    // public get codiacApiNatsUrl(): string {
    //   if (this.__codiacApiNatsUrl === undefined) {
    //     this.__codiacApiNatsUrl = this.localConfig?.apiNatsUrl ?? this._cliCfg.codiacNatsUrl ?? CodiacNatsClient.DEFAULTS.baseUrl;
    //   }
    //   return this.__codiacApiNatsUrl!; // <--- wtf this assertion operator is still needed, but we just ensured its not undefined ??
    // }
    // private __codiacApiNatsUrl: string | undefined;
    get codiacApiUrl() {
        var _a, _b, _c;
        if (this.__codiacApiUrl === undefined) {
            this.__codiacApiUrl = (_c = (_b = (_a = this.localConfig) === null || _a === void 0 ? void 0 : _a.apiUrl) !== null && _b !== void 0 ? _b : this._cliCfg.codiacApiBaseUrl) !== null && _c !== void 0 ? _c : codiac_api_1.CodiacRestClient.DEFAULT_API_URL;
        }
        return this.__codiacApiUrl; // <--- wtf this assertion operator is still needed, but we just ensured its not undefined ??
    }
    /**  TODO:  Get this out of the CLI.  Any calls to the codiac api should be made from the relay. */
    get _codiacApi() {
        if (this.__codiacApi === undefined) {
            this.__codiacApi = this.ioc.get(uilogic_1.INTERFACES_CLI_ENTERPRISE.ICodiacClient);
        }
        return this.__codiacApi;
    }
    get authClient() {
        if (this.__authClient === undefined) {
            this.__authClient = this.ioc.get(uilogic_1.INTERFACES_CLI_ENTERPRISE.IAuthClient);
        }
        return this.__authClient;
    }
    // protected get api(): ThrowingCodiacClient {
    //   if (this.__api === undefined) {
    //     this.__api = this.ioc.get(ThrowingCodiacClient);
    //   }
    //   return this.__api;
    // }
    // private __api: ThrowingCodiacClient | undefined;
    // protected get relayClient(): ExtendedRelayClient {
    //   if (this.__relayClient === undefined) {
    //     if (this._projectRoot !== undefined) { }
    //     // this.__relayClient = new RelayClient(this._userCntx, this._relayContainer, this._styler, this.logger);
    //     // this.__relayClient = new ExtendedRelayClient(this.ioc, this._userCntx, this._relayContainer, this._styler, this.logger);
    //     this.__relayClient = this.ioc.get<ExtendedRelayClient>(ExtendedRelayClient);
    //   }
    //   return this.__relayClient;
    // }
    // private __relayClient: ExtendedRelayClient | undefined;
    get genRelayClient() {
        if (this.__genRelayClient === undefined) {
            if (this._projectRoot !== undefined) { }
            // this.__relayClient = new RelayClient(this._userCntx, this._relayContainer, this._styler, this.logger);
            // this.__relayClient = new ExtendedRelayClient(this.ioc, this._userCntx, this._relayContainer, this._styler, this.logger);
            this.__genRelayClient = this.ioc.get(codiac_relay_1.RelayClient);
        }
        return this.__genRelayClient;
    }
    get msgClient() {
        if (this.__msgClient == undefined) {
            this.__msgClient = this.ioc.get(INTERFACES_CLI_1.INTERFACES_CLI.IMessagingClient);
        }
        return this.__msgClient;
    }
    get watcher() {
        if (this.__watcher == undefined) {
            this.__watcher = new lrp_watcher_predef_1.LrpWatcherPredef(this.msgClient, this.logger); // this.ioc.get(LrpWatcherPredef); // <--dont inject this so we dont create another relayWebSocket client instance
        }
        return this.__watcher;
    }
    set _relayContainer(rc) {
        this.__relayContainer = rc;
    }
    get _relayContainer() {
        var _a, _b, _c, _d, _e, _f;
        if (this.__relayContainer === undefined) {
            // HACK: Need an IoC strategy !!
            const _apiClientKind = (_c = (_b = (_a = this.localConfig) === null || _a === void 0 ? void 0 : _a.apiClientKind) !== null && _b !== void 0 ? _b : this._cliCfg.apiClientKind) !== null && _c !== void 0 ? _c : entities_1.ApiClientKindEnum.nats;
            const _useNats = Boolean(_apiClientKind == entities_1.ApiClientKindEnum.nats);
            const localEntities = type_safety_utils_1.TypeSafetyUtils.toBoolean(/* TEMP HACK!! --> update this class... */ (_e = (_d = this.localConfig) === null || _d === void 0 ? void 0 : _d.localEntities) !== null && _e !== void 0 ? _e : (_f = this._cliCfg) === null || _f === void 0 ? void 0 : _f.localEntities);
            this.__relayContainer = new relay_container_1.RelayContainer(this._styler, this.cliEnviro, this.logger, _useNats ? "nats://localhost:4222" : "http://localhost:5799/heartbeat-json", undefined, this._projectRoot, localEntities);
            // Pump out human readable status of what's happening relay container statuses
            this.__relayContainer.userMessages
                .pipe((0, operators_1.distinctUntilChanged)())
                .pipe((0, operators_1.map)(msg => {
                var _a;
                if (msg && !((_a = this.__relayContainer) === null || _a === void 0 ? void 0 : _a.silent))
                    this._ui.userMessage(`${this._styler.colorGood(msg)}`);
            }))
                .subscribe();
        }
        return this.__relayContainer;
    }
    get _userContextManager() {
        if (this.__userContextManager === undefined) {
            this.__userContextManager = new user_context_loader_1.UserContextManager(this.cliEnviro, this.authClient, this.logger);
        }
        return this.__userContextManager;
    }
    // TODO:  Make these all nullable
    // --- PROJECT SCOPE -----------------------------------------------------------
    // TODO: Try to get rid of this one.
    /** NOTE:  This property MUST ONLY be accessed from within a project folder.
   * It requires project scoped objects
   * such as: `projectRoot`, `projectConfig`, `projectUserConfig`, and `ProjectContextRepo`.
   *
   * It lazy-loads them, and its methods will fail without them.
  */
    get _ops() {
        if (this.__ops === undefined) {
            this.__ops = new ops_1.LocalOps(this.ioc); // this ctor is trivial, no effect on perf. Lazy loading here is just for back-compat.
        }
        return this.__ops;
    }
    get enterpriseContextor() {
        if (this.__enterpriseContextor === undefined) {
            // TODO: make this injectable
            // TODO: This ctor arg list is crazy.  Might want to break this class up somehow.
            this.__enterpriseContextor = new enterprise_contextualizer_1.EnterpriseContextualizer(this._userCntx.currentTenantCode, this._ops, this.genRelayClient, this._codiacApi, this._projCfg, this._projUserCfg, this.projCfgRepo, this._userCntx, this._userContextManager, this._ui, this._styler, (code) => this.exit(code), this.logger);
        }
        return this.__enterpriseContextor;
    }
    get rootMapUtils() {
        if (this._rootMapUtils_backer === undefined) {
            this._rootMapUtils_backer = this.ioc.get(rootmap_ui_utils_1.RootMapUiUtils);
        }
        return this._rootMapUtils_backer;
    }
    get exec() {
        if (this.__exec === undefined) {
            this.__exec = new argument_manager_1.ArgumentManager(this.id, this._projCfg, this.projCfgRepo, this.logger, this._ui);
        }
        return this.__exec;
    }
    /** This getter Lazyloads from ioc. */
    get projCfgRepo() {
        if (this.__projCfgRepo_isSet === undefined) {
            this.__projCfgRepo = this.ioc.get(data_1.ProjectContextRepo);
            this.__projCfgRepo_isSet = true;
        }
        return this.__projCfgRepo;
    }
    /** This getter Lazyloads from ioc. */
    get _projCfg() {
        if (this.__projCfg_isSet === undefined) {
            this.__projCfg = this.ioc.get(codiac_relay_contracts_1.ProjectConfig);
            this.__projCfg_isSet = true;
        }
        return this.__projCfg;
    }
    /** This getter Lazyloads from ioc. */
    get _projUserCfg() {
        if (this.__projUserCfg_isSet === undefined) {
            this.__projUserCfg = this.ioc.get(codiac_relay_contracts_1.ProjectUserConfig);
            this.__projUserCfg_isSet = true;
        }
        return this.__projUserCfg;
    }
    /** Lazyloads the project root folder path by walking up the current path to find a project config file. */
    get _projectRoot() {
        if (this.__projectRoot_isSet === undefined) {
            this.__projectRoot = ops_1.CliPathWalker.getProjectRoot(undefined, (this.requiresProjectScope === true));
            this.__projectRoot_isSet = true;
        }
        return this.__projectRoot;
    }
    /** Currently just coincides with projectRoot. */
    get _dockerRoot() {
        return this._projectRoot;
    }
    // private _dockerRoot: string|undefined;
    // --- END PROJECT SCOPE -----------------------------------------------------------
    /* == END OF LAZY LOADS ============================================================================================ */
    // /**
    //  * 
    //  * @deprecated Use `establishTenantContext()` instead.
    //  */
    // protected async loadCodiacContext(): Promise<UserContext> {
    //   return new Promise<UserContext>(async (resolve, reject) => {
    //     try {
    //       // let cliCfg = this._cfgRepo.readCliConfig();
    //       let codiacApiUrl = (this._cliCfg) ? this._cliCfg.codiacApiBaseUrl : undefined;
    //       let codiacApi = CodiacRestClient.create(this.logger, codiacApiUrl);
    //       let authApiUrl = (this._cliCfg) ? this._cliCfg.authApiBaseUrl : undefined;
    //       let authApi = AuthClient.create(this.logger, authApiUrl);
    //       let contextor = new TenantContextualizer(this._projCfg, authApi, codiacApi, this.projCfgRepo, this._ui, this._styler, this.logger);
    //       let cntx = await contextor.establishTenantContext();
    //       this.logger.debug("using codiac context:", cntx);
    //       resolve(cntx);
    //     } catch (err) {
    //       reject(err);
    //     }
    //   });
    // }
    /** Retrieves "all-the-things" from the api for the given enterprise. Throws not found or on error. */
    getRootMap(enterpriseCode) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                // TODO: Get this from the relay, so we can exploit local caching
                let crit = {};
                if (enterpriseCode && enterpriseCode.trim() != "") {
                    crit.enterprise = enterpriseCode;
                }
                let rootMapResult = yield this._codiacApi.Call.getRootMap(crit);
                if (rootMapResult.error)
                    throw rootMapResult.error;
                if (rootMapResult.output === undefined)
                    throw new Error(`No rootmap found for enterprise [${enterpriseCode}]`);
                this.logger.debug("Rootmap acquired for enterprise [".concat(enterpriseCode !== null && enterpriseCode !== void 0 ? enterpriseCode : "undefined", "]"));
                return rootMapResult.output;
            }
            catch (err) {
                err.message = "Error retrieving Rootmap from api: ".concat((_b = (_a = err.message) !== null && _a !== void 0 ? _a : err.name) !== null && _b !== void 0 ? _b : "(no error message provided, check logs for details)");
                throw err;
            }
        });
    }
    createAuditable() {
        let stamp = new Date(Date.now());
        return {
            created: stamp,
            createdBy: this._userCntx.userName,
            modified: stamp,
            modifiedBy: this._userCntx.userName
        };
    }
    /** Logs the user in as needed, and persists the new context object to the local machine. */
    bindUserInIoc(cntx) {
        var _a, _b;
        try {
            // Register it with the ioc container
            if (this.ioc.isBound(codiac_relay_contracts_1.UserContext)) {
                this.ioc.rebind(codiac_relay_contracts_1.UserContext).toConstantValue(cntx);
            }
            else {
                this.ioc.bind(codiac_relay_contracts_1.UserContext).toConstantValue(cntx);
            }
            // Do the same for the UserNameTenantCode obj
            let tenantUser = {
                username: cntx.userName,
                tenantCode: cntx.currentTenantCode // ! operator is ok because we just estab'd tenant context
            };
            if (this.ioc.isBound(codiac_ops_common_1.UserNameTenantCode)) {
                this.ioc.rebind(codiac_ops_common_1.UserNameTenantCode).toConstantValue(tenantUser);
            }
            else {
                this.ioc.bind(codiac_ops_common_1.UserNameTenantCode).toConstantValue(tenantUser);
            }
            if (cntx.currentToken) {
                let apiCreds = new codiac_messaging_2.TokenCreds(cntx.currentToken);
                if (this.ioc.isBound(codiac_messaging_2.TokenCreds)) {
                    this.ioc.unbind(codiac_messaging_2.TokenCreds);
                }
                this.ioc.bind(codiac_messaging_2.TokenCreds).toConstantValue(apiCreds);
                // Legacy token holder class
                let apiCreds_Legacy = new api_user_creds_1.ApiUserCreds(cntx.currentToken);
                if (this.ioc.isBound(api_user_creds_1.ApiUserCreds)) {
                    this.ioc.unbind(api_user_creds_1.ApiUserCreds);
                }
                this.ioc.bind(api_user_creds_1.ApiUserCreds).toConstantValue(apiCreds_Legacy);
            }
            // TenantUser
            // if (cntx.currentToken && cntx.currentTenantCode) {
            //   const encoder = new JwtEncoder();
            //   const tokenObj = encoder.tryDecode(cntx.currentToken);
            //   // let tenantUser = UserJwtMapper.read(tokenObj.payload);  // <-- this is in the auth sdk
            // }
            this.logger.debug("Bound user: ".concat((_a = tenantUser.username) !== null && _a !== void 0 ? _a : "anonymous", " [tenant: ", (_b = tenantUser.tenantCode) !== null && _b !== void 0 ? _b : "no tenant", "]"));
            return cntx;
        }
        catch (err) {
            throw err;
        }
    }
    /** Logs the user in as needed, and persists the new context object to the local machine. */
    establishTenantContext(currentContext, tenantContextualizer) {
        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, _b;
                try {
                    let contextor = tenantContextualizer !== null && tenantContextualizer !== void 0 ? tenantContextualizer : new uilogic_1.TenantContextualizer(this.cliEnviro, this._projCfg, this.authClient, this.projCfgRepo, this._ui, this._styler, this.logger);
                    let cntx = yield contextor.establishTenantContext(currentContext);
                    if (cntx.currentToken) {
                        this._codiacApi.setUserToken(cntx.currentToken); // why isnt this being done by the contextualizer?
                        this.authClient.setUserToken(cntx.currentToken); // why isnt this being done by the contextualizer?
                    }
                    this.bindUserInIoc(cntx);
                    // -----------------------------------------------
                    // Trigger reinstantiations
                    // COMMENTED OUT BC: this doesnt work.  No matter how hard I try, 
                    // I cant get the ioc to inject the newly minted ApiUserCreds 
                    // into the CodiacRestClient ctor.
                    // 
                    // this.__codiacApi = undefined;
                    // this.__api = undefined;
                    // -----------------------------------------------
                    // TODO: Use DataAuthProvider instead.
                    if (this.adminOnly && (((_b = (_a = this._userCntx.roles) === null || _a === void 0 ? void 0 : _a.includes(security_1.AUTH_ADMIN_ROLE_NAME)) !== null && _b !== void 0 ? _b : false) == false)) {
                        throw new Error("You are not authorized to execute this command.");
                    }
                    resolve(cntx);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** Resolves the interaction mode from the given command flags. */
    getInteractionMode(silentFlag, echoFlag, toScriptFlag) {
        var _a, _b;
        const interactionMode = (this.pipedInput) ? config_ui_utils_1.InteractionModes.silent : (_b = (_a = undefined !== null && undefined !== void 0 ? undefined : (echoFlag ? config_ui_utils_1.InteractionModes.echo : undefined)) !== null && _a !== void 0 ? _a : (toScriptFlag ? config_ui_utils_1.InteractionModes.toscript : undefined)) !== null && _b !== void 0 ? _b : (silentFlag ? config_ui_utils_1.InteractionModes.silent : undefined);
        return interactionMode;
    }
    /** Acquires and adopts the identity of a single enterprise for the current project
     * (DOES NOT establish an AssetBinding for the current tenant).
     * TODO: Move this to commandBase
     */
    establishEnterpriseContext(rootMap, enterpriseCode, interactionMode) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    // CAUTION:
                    // we are relying on this assertion:  `this._userCntx.currentTenantCode!`
                    // The tenantContexualizer went through great lengths 
                    // to ensure the _userCntx has a current tenant code,
                    // so we can safely use that assertion operator here.
                    // // This ctor arg list is crazy.  Might want to break this class up somehow.
                    // let contextor = new EnterpriseContextualizer(this._userCntx.currentTenantCode!, this._ops, this._codiacApi,
                    //   this._projCfg, this._projUserCfg, this.projCfgRepo,
                    //   this._userCntx, this._userContextManager, this._regClientFactory, this._ui, this._styler, (code) => this.exit(code), this.logger);
                    let enterprise = yield this.enterpriseContextor.establishEnterprise(rootMap, enterpriseCode, interactionMode);
                    resolve({ enterprise: enterprise });
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** Acquires and adopts the identity of a single enterprise (and asset) for the current project
     * (aka: establishes an AssetBinding for the current tenant).
     * TODO: return undefined to mean for "all in enterprise"
     * TODO: Move this to commandBase
     *
     * @param suppressConfirmations (Optional: defaults to false) Prevents confirmations of user-values that are remembered from prior runs.
     */
    establishAssetContext(enterprise, suppressConfirmations) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    let contextor = new enterprise_contextualizer_1.EnterpriseContextualizer(this._userCntx.currentTenantCode, this._ops, this.genRelayClient, this._codiacApi, this._projCfg, this._projUserCfg, this.projCfgRepo, this._userCntx, this._userContextManager, this._ui, this._styler, this.exit, this.logger);
                    // let enterprise = await contextor.establishEnterprise(enterpriseCode);
                    let assetName = yield contextor.establishEnterpriseAsset(enterprise, suppressConfirmations);
                    resolve([assetName]);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** Defaults to the cabinet declared in the project user config.
     * NOTE:  Run EstablishEnterpriseContext() before calling this method!!  It throws if no enterprise has been establiashed.
    */
    establishCabinetContext(requestedCabinet, requestedEnviro) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    let contextor = new enterprise_contextualizer_1.EnterpriseContextualizer(this._userCntx.currentTenantCode, this._ops, this.genRelayClient, this._codiacApi, this._projCfg, this._projUserCfg, this.projCfgRepo, this._userCntx, this._userContextManager, this._ui, this._styler, this.exit, this.logger);
                    let cabCntx = yield contextor.establishCabinetContext(requestedCabinet, undefined, requestedEnviro);
                    resolve(cabCntx);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** This is only here so we can get the cluster name.
     * Defaults to the cabinet declared in the project user config.
     * NOTE:  Run EstablishEnterpriseContext() before calling this method!!  It throws if no enterprise has been establiashed.
    */
    establishCabinet(requestedCabinet, suppressConfirmations) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                try {
                    let contextor = new enterprise_contextualizer_1.EnterpriseContextualizer(this._userCntx.currentTenantCode, this._ops, this.genRelayClient, this._codiacApi, this._projCfg, this._projUserCfg, this.projCfgRepo, this._userCntx, this._userContextManager, this._ui, this._styler, this.exit, this.logger);
                    let cabCntx = yield contextor.establishCabinet(requestedCabinet, suppressConfirmations);
                    resolve(cabCntx);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    /** UI dialogue to acquire a valid environment under the current tenant.  */
    establishEnvironment(requestedEnv) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let contextor = new environment_contextualizer_1.EnvironmentContextualizer(this._codiacApi, this._ui, this.logger);
                let env = yield contextor.establishEnvironment(requestedEnv);
                return env;
            }
            catch (err) {
                this._ui.userMessage(`Error establishing environment: ${(_a = err.name) !== null && _a !== void 0 ? _a : ""} ${(_b = err.message) !== null && _b !== void 0 ? _b : ""}`);
                throw err;
            }
        });
    }
    establishCloudProviderCreds(rootMap, clusterName, suppressConfirmations, providedUserName, providedSecret) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                if (clusterName === undefined)
                    throw new Error(`Cannot prompt for cloud provider credentials: cluster name provided was undefined.`);
                let targetClusterDef = rootMap.clusters.find(c => c.name === clusterName);
                if (targetClusterDef) {
                    yield this.cspContextualizer.promptForCloudProviderCreds(this.ioc, targetClusterDef.provider, suppressConfirmations, providedUserName, providedSecret, targetClusterDef.providerSubscriptionId);
                }
                else {
                    this.logger.warn(`No cluster defnition named ${clusterName} was found, so cloud provider creds may not be in scope.`);
                }
            }
            catch (err) {
                this._ui.userMessage(`Error establishing cloud provider credentials: ${(_a = err.name) !== null && _a !== void 0 ? _a : ""} ${(_b = err.message) !== null && _b !== void 0 ? _b : ""}`);
                throw err;
            }
        });
    }
}
exports.CommandBaseEnterprise = CommandBaseEnterprise;
//# sourceMappingURL=command-base-enterprise.js.map