"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.LogStreamer = exports.K8sContainerRef = exports.TermArgs = exports.ConfigFileArgs = exports.ExecArgs = exports.K8S_POD_PHASES = exports.AssetContentType = exports.PROMPT_ME_DESIGNATOR = void 0;
const tslib_1 = require("tslib");
const stream = require("stream");
const core_1 = require("@oclif/core");
const _ = require("lodash");
const SplitCmd = require('split-cmd');
const request = require("request");
const semver = require("semver");
const k8s = require("@kubernetes/client-node");
//TODO this could be a problem is future  releases
const web_socket_handler_1 = require("@kubernetes/client-node/dist/web-socket-handler");
const codiac_domain_1 = require("@codiac.io/codiac-domain");
const command_base_enterprise_1 = require("../../command-base-enterprise");
const contracts_1 = require("../../apis/codiac-api/contracts");
const CodiacConstants = require("../../codiac-constants");
const render = require("../../uilogic/render-methods");
const cloud_provider_contextualizer_1 = require("../../uilogic/cloud-provider-contextualizer");
const ops_1 = require("../../ops");
const config_ui_utils_1 = require("../../uilogic/config-ui-utils");
// let logUpdate: any;
// (async function () {
//   logUpdate = (await import("log-update")).default;
// })()
// import * as logUpdate from "log-update";
// import logUpdate from "log-update";
// const logUpdate = (await import("log-update/index.js")).default
// import { logUpdate } from "log-update";
// const logUpdate = require("log-update");
const log_update_wrapper_1 = require("../../log-update-wrapper");
const codiac_constants_1 = require("../../codiac-constants");
const config_ui_utils_2 = require("../../uilogic/config-ui-utils");
const k8s_utils_1 = require("../../ops/k8s/k8s-utils");
const type_safety_utils_1 = require("../../uilogic/type-safety-utils");
// const { selectFiles, COMPLETED, CANCELLED } = require('select-files-cli');  // gd js wo ts...
// const { selectFiles, COMPLETED, CANCELLED } = require('../../uilogic/file-selector');  // gd js wo ts...
/** The value provided as input that indicates
 * a user's desire to be prompted with a list from which choose the value(s),
 * instead of entering them manually or taking a default. */
exports.PROMPT_ME_DESIGNATOR = "?";
var AssetContentType;
(function (AssetContentType) {
    AssetContentType["logs"] = "logs";
    AssetContentType["term"] = "term";
    AssetContentType["exec"] = "exec";
    AssetContentType["env"] = "env";
    AssetContentType["config"] = "config";
    AssetContentType["status"] = "status";
    // | "footprint-usage" | "infrx" 
    // | "ingress-domains" | "ingress-nslookup" | "ingress-routes" | "ingress-logs" | "ssl-certs" | "ssl-logs" | "ssl-cert-history";
})(AssetContentType = exports.AssetContentType || (exports.AssetContentType = {}));
const DEFAULT_TERMINAL_STARTER = "bash";
/** The quantity of lines of backlog to include in the log output. */
const DEFAULT_LOG_TAIL = 10;
/** This belongs to k8s - not us, but @kubernetes/client-node has no enum or constants for these magic strings...
 *
 * @see https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
*/
var K8S_POD_PHASES;
(function (K8S_POD_PHASES) {
    K8S_POD_PHASES["Pending"] = "Pending";
    K8S_POD_PHASES["Running"] = "Running";
    K8S_POD_PHASES["Succeeded"] = "Succeeded";
    K8S_POD_PHASES["Failed"] = "Failed";
    K8S_POD_PHASES["Unknown"] = "Unknown";
})(K8S_POD_PHASES = exports.K8S_POD_PHASES || (exports.K8S_POD_PHASES = {}));
class AssetView extends command_base_enterprise_1.CommandBaseEnterprise {
    constructor() {
        super(...arguments);
        this.takeDefaults = false;
    }
    get uiCloudPvd() {
        if (this._uiCloudPvd_backer === undefined) {
            this._uiCloudPvd_backer = this.ioc.get(cloud_provider_contextualizer_1.CloudProviderContextualizer);
        }
        return this._uiCloudPvd_backer;
    }
    // --------------------------------------------------------------------
    // Lazy-loaded properties
    get configUtils() {
        if (this._configUtils_backer === undefined) {
            this._configUtils_backer = this.ioc.get(config_ui_utils_2.ConfigUiUtils);
        }
        return this._configUtils_backer;
    }
    get k8sUtils() {
        if (this._k8sUtils_backer === undefined) {
            this._k8sUtils_backer = this.ioc.get(k8s_utils_1.K8sUtils);
        }
        return this._k8sUtils_backer;
    }
    // --------------------------------------------------------------------
    bootstrap() {
        super.bootstrap();
        cloud_provider_contextualizer_1.CloudProviderContextualizer.bootstrap(this.ioc); // (idempotent) this is a dependency of the configurators
        this.ioc.bind(config_ui_utils_2.ConfigUiUtils).toSelf();
        k8s_utils_1.K8sUtils.bootstrap(this.ioc, this);
    }
    runAsync() {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(AssetView);
            let partialReq = {};
            partialReq.enterprise = flags.enterprise;
            partialReq.asset = flags.asset;
            partialReq.environment = flags.environment;
            partialReq.cabinet = flags.cabinet;
            partialReq.content = (flags.type) ? type_safety_utils_1.TypeSafetyUtils.toEnum(AssetContentType, flags.type) : undefined;
            partialReq.replica = flags.replica;
            let givenCmd;
            if (args.cmd) {
                givenCmd = args.cmd;
                let isep = this.argv.indexOf("--");
                if (isep >= 0) {
                    if (isep + 1 < this.argv.length) {
                        givenCmd = this.argv.slice(isep + 1);
                    }
                    else {
                        givenCmd = undefined;
                    }
                }
            }
            let contentOptions = {
                follow: flags.logsFollow,
                tailLines: flags.logsTail,
                /* tty: flags.tty, */
                command: givenCmd,
                terminalStartup: flags.terminal,
                rootPathName: flags.configFile
            };
            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);
            this.takeDefaults = (_c = flags.takeDefaults) !== null && _c !== void 0 ? _c : false;
            // ==================================================
            // 3. Set context
            // ==================================================
            this._userCntx = yield this.establishTenantContext(this._userCntx);
            let rootMap = yield this.getRootMap();
            let enterprise = (yield this.establishEnterpriseContext(rootMap, partialReq.enterprise, interactionMode)).enterprise;
            _.remove(rootMap.enterprises, e => e.name != enterprise.name); // trim down to match legacy conditions
            partialReq.enterprise = enterprise.name;
            // ==================================================
            // 3.1 Assemble candidate
            // ==================================================
            // let candidate: AssetContentRequest;
            // let cmd: string[] | undefined;
            const candidate = (interactionMode == config_ui_utils_1.InteractionModes.silent) ?
                // candidate = await this.buildCandidate_silently(partialReq, partialReq.content, contentOptions);
                yield this.buildCandidate_silently({ partialReq, contentOptions, interactionMode }, rootMap)
                :
                    // [candidate, cmd] = await this.buildCandidate_interactively(partialReq, contentOptions, partialReq.content);
                    yield this.buildCandidate_interactively({ partialReq, contentOptions, interactionMode }, rootMap);
            // ==================================================
            // 4. Render ultimate command string
            // ==================================================
            //Why not let the method that builds the command output or not
            // if (interactionMode == InteractionModes.echo || interactionMode == InteractionModes.toscript) {
            //   if (cmd && cmd.length > 0) {
            //     this._ui.userMessage(cmd.join(" "));
            //   }
            // }
            // ==================================================
            // 5. Execute
            // ==================================================
            if (interactionMode != config_ui_utils_1.InteractionModes.toscript) {
                yield this.renderSelectedContent(candidate.context, candidate.contentType, candidate.k8sEntities, candidate.contentOptions, candidate.replicas);
            }
        });
    }
    captureArgs() {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(AssetView);
            let partial = {};
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            let repReq = {};
            repReq.enterprise = flags.enterprise;
            repReq.asset = flags.asset;
            repReq.environment = flags.environment;
            repReq.cabinet = flags.cabinet;
            repReq.content = (flags.type) ? type_safety_utils_1.TypeSafetyUtils.toEnum(AssetContentType, flags.type) : undefined;
            repReq.replica = flags.replica;
            let givenCmd;
            if (args.cmd) {
                givenCmd = args.cmd;
                let isep = this.argv.indexOf("--");
                if (isep >= 0) {
                    if (isep + 1 < this.argv.length) {
                        givenCmd = this.argv.slice(isep + 1);
                    }
                    else {
                        givenCmd = undefined;
                    }
                }
            }
            partial.contentOptions = {
                follow: flags.logsFollow,
                tailLines: flags.logsTail,
                /* tty: flags.tty, */
                command: givenCmd,
                terminalStartup: flags.terminal,
                rootPathName: flags.configFile
            };
            // ---------------------------------------------------------------
            // TODO: move everything from here down into the base class
            // ---------------------------------------------------------------
            const interactionMode = (this.pipedInput) ? config_ui_utils_1.InteractionModes.silent : (_b = (_a = undefined !== null && undefined !== void 0 ? undefined : (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 = flags['take-defaults'];
            return [partial, interactionMode, takeDefaults];
        });
    }
    // private async buildCandidate_silently(partialReq: Partial<AssetReplicaContentRequest>, content: AssetContentType | undefined, contentOptions: Partial<LogOptions> | Partial<ExecArgs> | Partial<TermArgs> | Partial<ConfigFileArgs>): Promise<AssetContentRequest> {
    buildCandidate_silently(buildCandidateOptions, rootMap) {
        var _a, _b, _c, _d, _e, _f, _g;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const partialReq = buildCandidateOptions.partialReq;
            const contentOptions = buildCandidateOptions.contentOptions;
            const content = partialReq.content;
            this.__ui = new ops_1.ThrowingUserInputProvider(this.logger, "suppress");
            if (content === undefined || _.isEmpty(partialReq.content))
                throw new Error(`No content type specified.`);
            if (partialReq.enterprise === undefined || _.isEmpty(partialReq.enterprise))
                throw new Error(`No enterprise specified.`);
            if (partialReq.asset === undefined || _.isEmpty(partialReq.asset))
                throw new Error(`No asset specified.`);
            if (partialReq.environment === undefined || _.isEmpty(partialReq.environment))
                throw new Error(`No environment specified.`);
            if (partialReq.cabinet === undefined || _.isEmpty(partialReq.cabinet))
                throw new Error(`No cabinet specified.`);
            // Retrieve the list of replicas for the given cabinet.
            let ent = rootMap.enterprises.find(e => e.name == partialReq.enterprise);
            if (ent == undefined)
                throw new Error("Given enterprise was not found.");
            let asset = ent.assets.find(a => a.name == partialReq.asset);
            if (asset == undefined)
                throw new Error("Given asset was not found.");
            partialReq.assetType = asset.type;
            let env = this.configUtils.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap); // this is fkng stupid.  Put this value into the cab value
            let cabObj = this.configUtils.getCabinetInfrx(partialReq.enterprise, env.name, partialReq.cabinet, rootMap);
            if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
                throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
            let k8sObj = { namespace: cabObj.infrx.namespace };
            let options;
            let replicas;
            if (partialReq.assetType == contracts_1.AssetTypesEnum.helm) {
                // Enforce the only view that a helm asset can invoke
                if (partialReq.content == undefined)
                    partialReq.content = AssetContentType.config;
                if (partialReq.content != AssetContentType.config) {
                    throw new Error("Invalid content type.  Helm assets can only invoke a config view.");
                }
                options = new ConfigFileArgs(undefined, codiac_domain_1.SpecialConfigTypesEnum.helm); // WTF, the JS syntax was supposed to allow this assignment without requiring a cast like this...
            }
            else {
                // SELECT REPLICA
                // Replica should not be required 
                // (though this can be confusing when there's more than one; 
                // the user will have to know they're only getting a single replica of logs, 
                // and they need to know they might have to call out for one.
                // if (partialReq.replica === undefined || _.isEmpty(partialReq.replica)) throw new Error(`No replica specified.`);
                switch (partialReq.content) {
                    case AssetContentType.logs:
                        options = (contentOptions !== null && contentOptions !== void 0 ? contentOptions : {});
                        // defaults?
                        break;
                    case AssetContentType.exec:
                        if (_.isEmpty(contentOptions.command))
                            throw new Error(`No command specified.`);
                        const cmdObj = (_a = contentOptions.command) !== null && _a !== void 0 ? _a : [];
                        options = {
                            command: typeof cmdObj === 'string' ? cmdObj.split(" ") : cmdObj,
                            tty: (_b = contentOptions.tty) !== null && _b !== void 0 ? _b : false
                        };
                        break;
                    case AssetContentType.config:
                        if (_.isEmpty(contentOptions.rootPathName))
                            throw new Error(`No file specified.`);
                        options = {
                            rootPathName: contentOptions.rootPathName
                        };
                        break;
                    case AssetContentType.term:
                        options = {
                            terminalStartup: (_c = contentOptions.terminalStartup) !== null && _c !== void 0 ? _c : DEFAULT_TERMINAL_STARTER
                        };
                        break;
                    case AssetContentType.env: /* env has no user input */
                    default:
                        options = {};
                        break;
                }
                replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
                if (replicas.length > 0) {
                    // Capture the user's "any" override.
                    let anyReplica = false;
                    if (partialReq.replica === CodiacConstants.CliConstants.ARGUMENT_VALUE_FOR_ANY) {
                        anyReplica = true;
                        delete partialReq.replica;
                    }
                    // Find the requested replica
                    let found;
                    if (partialReq.replica) {
                        found = replicas.find(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) === partialReq.replica; });
                        if (!found) {
                            throw new Error(`Specified replica was not found.`);
                        }
                    }
                    // Force a replica selection (unless it's an asset-level operation, where replica is optional)
                    if (content !== AssetContentType.status) {
                        // Set first as default
                        if (!found) {
                            found = replicas[0];
                        }
                    }
                    // Finally, grab any selected replica
                    if (found) {
                        k8sObj = {
                            namespace: cabObj.infrx.namespace,
                            pod: (_e = (_d = found.metadata) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "unnamed",
                            container: (_g = (_f = found.spec) === null || _f === void 0 ? void 0 : _f.containers[0].name) !== null && _g !== void 0 ? _g : "unnamed"
                        };
                        partialReq.replica = k8sObj.pod;
                    }
                }
            }
            // Assemble 
            let candidate = {
                enterprise: partialReq.enterprise,
                context: {
                    enterprise: partialReq.enterprise,
                    environment: partialReq.environment,
                    asset: partialReq.asset,
                    assetType: partialReq.assetType,
                    cabinet: partialReq.cabinet
                },
                contentType: content,
                contentOptions: options,
                k8sEntities: k8sObj
            };
            if (partialReq.replica)
                candidate.context.replica = partialReq.replica;
            if (replicas)
                candidate.replicas = replicas;
            return candidate;
        });
    }
    // private async buildCandidate_interactively(partialReq: Partial<AssetReplicaContext>, contentOptions: ContentArguments, content?: AssetContentType): Promise<[AssetContentRequest, string[]]> {
    buildCandidate_interactively(buildCandidateOptions, rootMap) {
        var _a, _b, _c, _d;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const partialReq = buildCandidateOptions.partialReq;
            let contentOptions = buildCandidateOptions.contentOptions;
            let content = partialReq.content;
            let enterprise = rootMap.enterprises.find(e => e.name == partialReq.enterprise); // Assertion ok bc ent contextualizer ensured a valid ent 
            let replicas;
            let k8sObj;
            let confirmed = false;
            let optionsArgs = [];
            do {
                // 1.  Select Asset
                partialReq.asset = yield this.promptForAsset(enterprise.assets, partialReq.asset);
                const asset = (enterprise.assets.find(a => a.name == partialReq.asset));
                partialReq.assetType = asset.type;
                // 2. Cabinet
                let [cabObj, enviro] = yield this.configUtils.promptForCabinet(partialReq.enterprise, rootMap, partialReq.cabinet);
                partialReq.cabinet = cabObj.name;
                partialReq.environment = enviro; // this.deriveEnvironmentFrom(partialReq.enterprise, partialReq.cabinet, rootMap).name;
                let cluster = this.deriveClusterFrom(partialReq.enterprise, partialReq.environment, partialReq.cabinet, rootMap);
                // partialReq.cabinet = await this.establishCabinetContext(partialReq.cabinet);  
                if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
                    throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
                k8sObj = { namespace: cabObj.infrx.namespace };
                // 3. Content type
                content = yield this.promptForContentType(partialReq.assetType, content);
                // 4. Content-specific arguments
                // MarkStartHere("implement prompt-me designator.")
                // MarkStartHere("Support the current logger or ioc ctr inside the ws event handlers");
                // MarkStartHere("Need UI to operate a different stream than stdout (so piping stdout wont include the ui content");
                [contentOptions, optionsArgs] = yield this.promptForContentOptions(content, partialReq, partialReq.assetType, contentOptions);
                // 5. Authenticate with CSP
                this.uiCloudPvd.takeDefaults = this.takeDefaults;
                yield this.uiCloudPvd.promptForCloudProviderCreds(this.ioc, cluster.provider, undefined, undefined, undefined, cluster.providerSubscriptionId);
                confirmed = true;
                if (partialReq.assetType == contracts_1.AssetTypesEnum.helm) {
                    // Nothing to do;  We'll be looking at the helm chart release, not pods.
                }
                else {
                    // 6. Replica (Pod)
                    if (cabObj.infrx == undefined || _.isEmpty(cabObj.infrx))
                        throw new Error(`Cannot connect to cabinet ${cabObj.name}: it has no infrastructure record.`);
                    replicas = yield this.fetchReplicas(partialReq, cabObj.infrx.namespace);
                    if (replicas.length > 0) {
                        // Capture the user's "any" override.
                        let anyReplica = false;
                        if (partialReq.replica === CodiacConstants.CliConstants.ARGUMENT_VALUE_FOR_ANY) {
                            anyReplica = true;
                            delete partialReq.replica;
                        }
                        // Set first as default
                        partialReq.replica = (_b = (_a = replicas[0].metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
                        k8sObj = {
                            namespace: cabObj.infrx.namespace,
                            pod: partialReq.replica,
                            container: (_d = (_c = replicas[0].spec) === null || _c === void 0 ? void 0 : _c.containers[0].name) !== null && _d !== void 0 ? _d : "unnamed"
                        };
                        // Select a replica unless it's an asset-level operation
                        if (content !== AssetContentType.status) {
                            if ((replicas.length > 1) && (anyReplica !== true)) {
                                k8sObj = yield this.promptForReplica(replicas, undefined, partialReq.replica);
                                partialReq.replica = k8sObj.pod;
                            }
                        }
                    }
                    else {
                        this._ui.userMessage(this._styler.colorWarning(`No [${partialReq.asset}] replicas found in [${cabObj.name}]`));
                        confirmed = false;
                    }
                }
                // 7. Confirm or loop back around to enterprise
                // confirmed = true; // This is a readonly ui (no danger), and we want to enable fast switching among diff content types, so let's not waste time confirming.  // await this._ui.promptConfirm("confirm", "Apply? ");
            } while (!confirmed);
            // We're hard-coding instead of casting here to validate at build-time that each partial property is fully-hydrated.
            // Assemble 
            let candidate = {
                enterprise: partialReq.enterprise,
                context: {
                    enterprise: partialReq.enterprise,
                    environment: partialReq.environment,
                    asset: partialReq.asset,
                    assetType: partialReq.assetType,
                    cabinet: partialReq.cabinet
                },
                contentType: content,
                contentOptions: contentOptions,
                k8sEntities: k8sObj
            };
            if (partialReq.replica)
                candidate.context.replica = partialReq.replica;
            if (replicas)
                candidate.replicas = replicas;
            // Build command string
            if (buildCandidateOptions.interactionMode == config_ui_utils_1.InteractionModes.echo || buildCandidateOptions.interactionMode == config_ui_utils_1.InteractionModes.toscript) {
                const cmd = ["cod", "asset", "view"];
                cmd.push("--silent");
                cmd.push("-e", candidate.context.enterprise);
                cmd.push("-a", candidate.context.asset);
                cmd.push("-n", candidate.context.environment);
                cmd.push("-c", candidate.context.cabinet);
                if (candidate.context.replica)
                    cmd.push("-r", candidate.context.replica);
                cmd.push("-t", candidate.contentType);
                if (Array.isArray(optionsArgs) && optionsArgs.length > 0) {
                    if (optionsArgs.length > 1)
                        cmd.push(`'${optionsArgs.join(" ")}'`);
                    else
                        cmd.push(...optionsArgs);
                }
                this._ui.userMessage(cmd.join(" "));
            }
            return candidate;
        });
    }
    promptForContentOptions(contentType, context, assetType, defaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let cmdArgs = [];
            try {
                switch (contentType) {
                    case AssetContentType.logs:
                        let logArgs = yield this.promptForLogOptions(defaults);
                        if (logArgs.follow)
                            cmdArgs.push("-f");
                        if (logArgs.tailLines)
                            cmdArgs.push(...["-l", "" + logArgs.tailLines]);
                        return [logArgs, cmdArgs];
                    case AssetContentType.exec:
                        let execArgs = yield this.promptForExecOptions(defaults);
                        cmdArgs.push(...execArgs.command);
                        return [execArgs, cmdArgs];
                    case AssetContentType.config:
                        this.enterpriseContextor.takeDefaults = this.takeDefaults;
                        // let rootPathName = (await this.enterpriseContextor.promptForTargetFile(context.enterprise, context.asset, (<ConfigFileArgs | undefined>defaults)?.rootPathName))!;
                        let rootPathName = defaults === null || defaults === void 0 ? void 0 : defaults.rootPathName;
                        let configType = defaults === null || defaults === void 0 ? void 0 : defaults.configType;
                        let typeFileChanged;
                        let existingSettings;
                        [configType, rootPathName, existingSettings, typeFileChanged] = yield this.configUtils.promptForTypeAndFile(context.enterprise, context.asset, assetType, configType, rootPathName, undefined, true, false);
                        let cfgArgs = {};
                        if (rootPathName) {
                            cfgArgs.rootPathName = rootPathName;
                            cmdArgs.push("-F", rootPathName);
                        }
                        if (configType) {
                            cfgArgs.configType = configType;
                            cmdArgs.push("-T", configType);
                        }
                        return [cfgArgs, cmdArgs];
                    case AssetContentType.term:
                        let termArgs = yield this.promptForTerminalOptions(defaults);
                        if (termArgs.terminalStartup)
                            cmdArgs.push(...["--terminal", termArgs.terminalStartup]);
                        return [termArgs, cmdArgs];
                    default:
                        return [{}, []];
                }
            }
            catch (err) {
                throw err;
            }
        });
    }
    promptForLogOptions(defaults) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let options = (defaults !== null && defaults !== void 0 ? defaults : {});
            options.follow = (_a = options.follow) !== null && _a !== void 0 ? _a : true;
            if (!this.takeDefaults) {
                options.follow = yield this._ui.promptConfirm("follow", "Stream logs? ", options.follow);
            }
            options.tailLines = (_b = options.tailLines) !== null && _b !== void 0 ? _b : DEFAULT_LOG_TAIL;
            if (!this.takeDefaults) {
                options.tailLines = yield this._ui.prompt("tail", "Lines of backlog (-1 for all):", true, options.tailLines);
            }
            return options;
        });
    }
    promptForExecOptions(defaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let options = (defaults !== null && defaults !== void 0 ? defaults : {});
            // Command
            let cmdStr;
            let keep = this.takeDefaults;
            if (!_.isEmpty(options.command) && !this.takeDefaults) {
                cmdStr = (typeof options.command === 'string') ? options.command : options.command.join(" ");
                keep = yield this._ui.promptConfirm("keepCommand", `Command: ${this._styler.hilite(cmdStr)} `);
            }
            if (keep && !_.isEmpty(options.command)) {
                options.command = (typeof options.command === 'string') ? options.command.split(" ") : options.command;
                // do nothing
            }
            else {
                options.command = (yield this._ui.prompt("command", "Command: ", true, cmdStr));
                options.command = SplitCmd.split(options.command); // no types declarations - f#$&*ing script kiddie.
                // the one above trips on the --output flag in this:   kubectl get pods -n cod-zombie-v1 -l assetNamme=codiac-api --output=jsonpath="{.items[*]['metadata.name', 'status.capacity']}"
                // something safer than: options.command = options.command.split(" ");
            }
            return options;
        });
    }
    promptForTerminalOptions(defaults) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let options = (defaults !== null && defaults !== void 0 ? defaults : {});
            // Command
            let keep = this.takeDefaults;
            if (!_.isEmpty(options.terminalStartup) && !this.takeDefaults) {
                keep = yield this._ui.promptConfirm("keepStartup", `Terminal Startup: ${this._styler.hilite(options.terminalStartup)} `);
            }
            if (keep && !_.isEmpty(options.terminalStartup)) {
                // do nothing
            }
            else {
                options.terminalStartup = (yield this._ui.prompt("startup", "Terminal Startup: ", true, options.terminalStartup));
            }
            return options;
        });
    }
    promptForContentType(assetType, defaultValue) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let output;
                let choices = Object.keys(AssetContentType);
                if (assetType == contracts_1.AssetTypesEnum.helm) {
                    // Enforce the only view that a helm asset can invoke
                    choices = [AssetContentType.config];
                }
                if (choices.length == 1) {
                    // select the one and only and inform the user
                    const contentType = type_safety_utils_1.TypeSafetyUtils.toEnum(AssetContentType, choices[0]);
                    if (contentType == undefined)
                        throw new Error("Unrecognized AssetContentType.");
                    output = contentType;
                    this._ui.userMessage("Type of content: ".concat(this._styler.hilite(output)));
                }
                else {
                    let keep = this.takeDefaults;
                    if (defaultValue && choices.find(x => x == defaultValue) && !this.takeDefaults) {
                        keep = yield this._ui.promptConfirm("keepType", `Type of content: ${this._styler.hilite(defaultValue)} `);
                    }
                    if (keep && defaultValue !== undefined) {
                        output = defaultValue;
                    }
                    else {
                        output = (yield this._ui.promptSelect("type", "Type of content: ", choices));
                    }
                }
                return output;
            }
            catch (err) {
                throw err;
            }
        });
    }
    promptForAsset(assets, defaultValue) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let output;
                let choices = assets.map(a => { return { name: a.name, value: a.name }; });
                choices = _.orderBy(choices, c => c.name);
                /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults)  */
                let changedUserInput = false;
                if (choices.length === 1) {
                    if (defaultValue != choices[0].value) {
                        changedUserInput = !_.isEmpty(defaultValue);
                        defaultValue = choices[0].value;
                    }
                }
                let keep = this.takeDefaults;
                if (defaultValue && choices.find(x => x.value == defaultValue) && (changedUserInput || !this.takeDefaults)) {
                    keep = yield this._ui.promptConfirm("keepAsset", `Asset: ${this._styler.hilite(defaultValue)} `);
                }
                if (keep && defaultValue !== undefined) {
                    output = defaultValue;
                }
                else {
                    output = (yield this._ui.promptSelect("asset", "Asset: ", choices));
                }
                return output;
            }
            catch (err) {
                throw err;
            }
        });
    }
    // private async promptForCabinet(enterprise: string, rootMap: RootMap, defaultValue?: string | undefined): Promise<CabinetClusterRoot> {
    //   try {
    //     let output: string;
    //     // render cab tree with all lines selectable
    //     let cabTree = this.buildCabinetTree(rootMap);
    //     let choices = this.buildSelectChoicesFrom(cabTree);
    //     // ISSUES:
    //     // 0. Remove the freaking lines from the selected value.
    //     // 1. Remember the last cabinet (user's enterprise context).
    //     // 2. We should only render the cabinets that actually contain a deployment of the asset (or dim the others and loop back if selected)
    //     // 3. The picklist should render the cluster (provider, name, location) 
    //     // 4. PERHAPS?  The version of the asset running in the selected cabinet should get rendered (either in the picklist or after the cab is selected)
    //     /** If we changed the input they provided, we need their confirmation (whether or not they said takeDefaults)  */
    //     const CAB_PREFIX = "cabinet|";
    //     let cabChoices = choices.filter(c => c.value.startsWith(CAB_PREFIX));
    //     let changedUserInput = false;
    //     if (cabChoices.length === 1) {
    //       if (defaultValue != cabChoices[0].value.slice(CAB_PREFIX.length)) {
    //         changedUserInput = !_.isEmpty(defaultValue);
    //         defaultValue = cabChoices[0].value.slice(CAB_PREFIX.length);
    //       }
    //     }
    //     let keep = this.takeDefaults;
    //     if (defaultValue && Boolean(choices.find(x => x.value === `${CAB_PREFIX}${defaultValue}`)) && (changedUserInput || !this.takeDefaults)) {
    //       keep = await this._ui.promptConfirm("keepCabinet", `Cabinet: ${this._styler.hilite(defaultValue)} `);
    //     }
    //     if (keep && defaultValue !== undefined) {
    //       output = defaultValue;
    //     } else {
    //       let scope: string | undefined;
    //       let target: string | undefined;
    //       do {
    //         if (scope === "environment") {
    //           // we could just filter it down from here...
    //         }
    //         let selection = (await this._ui.promptSelect("cabinet", "Cabinet: ", choices, false, false))!;
    //         let parts = selection.split("|");
    //         scope = parts[0];
    //         target = parts[1];
    //       } while (scope !== "cabinet")   // ensure they select a cabinet
    //       output = target;
    //     }
    //     let env = this.deriveEnvironmentFrom(enterprise, output, rootMap);  // this is fkng stupid.  Put this value into the cab value
    //     let cabObj = this.getCabinetInfrx(enterprise, env.name, output, rootMap);
    //     // return output;
    //     return cabObj;
    //   } catch (err) {
    //     throw (err);
    //   }
    // }
    // protected deriveEnvironmentFrom(enterprise: string, cabinet: string, rootMap: RootMap): EnvironmentRoot {
    //   try {
    //     let ent = rootMap.enterprises.find(e => e.name === enterprise);
    //     if (ent === undefined) throw new Error(`Cannot find environment: did not recognize enterprise [${enterprise}]`);
    //     let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
    //     if (enviro === undefined) throw new Error(`Cannot find environment: did not recognize cabinet [${cabinet}]`);
    //     return enviro;
    //   } catch (err) {
    //     throw err;
    //   }
    // }
    deriveClusterFrom(enterprise, environment, cabinet, rootMap) {
        try {
            let ent = rootMap.enterprises.find(e => e.name === enterprise);
            if (ent === undefined)
                throw new Error(`Cannot find cluster: did not recognize enterprise [${enterprise}]`);
            let enviro = ent.environments.find(x => x.cabinets.find(c => c.name === cabinet));
            if (enviro === undefined)
                throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
            let cabObj = enviro.cabinets.find(c => c.name === cabinet);
            if (cabObj == undefined)
                throw new Error(`Cannot find cluster: did not recognize cabinet [${cabinet}]`);
            if (cabObj.cluster == undefined)
                throw new Error(`Cannot find cluster: cabinet [${cabinet}] does not have a cluster specified.`);
            let cluster = rootMap.clusters.find(c => c.name == cabObj.cluster);
            if (cluster == undefined)
                throw new Error(`Did not recognize cluster [${cabObj.cluster}]`);
            return cluster;
        }
        catch (err) {
            throw err;
        }
    }
    buildSelectChoicesFrom(tree) {
        try {
            let choices = [];
            // the value is no good here - need scope and target both available
            render.renderStringTree(tree, (txt, item) => choices.push({ name: txt, value: item.value }));
            // // This is one way to do it
            // for (let item of tree) {
            // 
            //   let thisChoice: PromptChoice = { name: item.text, value: item.text };
            //   choices.push(thisChoice);
            // 
            //   if (item.children && item.children.length > 0) {
            //     let children = this.buildSelectChoicesFrom(item.children);
            //     choices.push(...children);
            //   }
            // }
            return choices;
        }
        catch (err) {
            throw err;
        }
    }
    // Commented out bc now using ConfigUiUtils
    // /** sets each value to "scope|target".
    //  * 
    //  * This is MOSTLY a COPY-PASTE from the CabinetList command!!!  This view is prob gonna be pretty common - consider promoting it to a shared utility. */
    // private buildCabinetTree(rootMap: RootMap, existings?: ScopedSetting[]): TextValueParent[] {
    //   let tree: TextValueParent[] = [];
    // 
    //   for (let ent of rootMap.enterprises) {
    //     let entBranch: TextValueParent = { text: `${ent.name} enterprise:`, value: `${ScopeLevel.enterprise}|${ent.name}` };
    //     let entSetting = existings?.find(s => s.scope === ScopeLevel.enterprise && s.target === ent.name);
    //     if (entSetting !== undefined) {
    //       let valueSuffix = this.ellipsis(35, entSetting.value ?? "[set to undefined]");
    //       valueSuffix = `(${valueSuffix})`;
    //       entBranch.text = entBranch.text.concat(" ", this._styler.dim(valueSuffix));
    //     }
    // 
    //     for (let env of _.sortBy(ent.environments, e => e.sequence, e => e.name)) {
    //       let envBranch: TextValueParent = { text: `${env.name}`, value: `${ScopeLevel.environment}|${env.name}` }
    //       let envSetting = existings?.find(s => s.scope === ScopeLevel.environment && s.target === env.name);
    //       if (envSetting !== undefined) {
    //         let valueSuffix = this.ellipsis(35, envSetting.value ?? "[set to undefined]");
    //         valueSuffix = `(${valueSuffix})`;
    //         envBranch.text = envBranch.text.concat(" ", this._styler.dim(valueSuffix));
    //       }
    // 
    //       for (let cab of env.cabinets) {
    //         // let cwg = rootMap.clusters.find(c => c.name === cab.cluster);
    //         // let clusterDesc = cwg ? ` (${cab.cluster}, ${cwg.provider} ${cwg.locationName})` : "";
    //         let cabBranch: TextValueParent = {
    //           text: `${cab.name}`,
    //           value: `${ScopeLevel.cabinet}|${cab.name}`
    //         }
    //         let cabSetting = existings?.find(s => s.scope === ScopeLevel.cabinet && s.target === cab.name);
    //         if (cabSetting !== undefined) {
    //           let valueSuffix = this.ellipsis(35, cabSetting.value ?? "[set to undefined]");
    //           valueSuffix = `(${valueSuffix})`;
    //           cabBranch.text = cabBranch.text.concat(" ", this._styler.dim(valueSuffix));
    //         }
    // 
    //         if (envBranch.children === undefined) envBranch.children = [];
    //         envBranch.children?.push(cabBranch)
    //       }
    // 
    //       if (entBranch.children === undefined) entBranch.children = [];
    //       entBranch.children.push(envBranch);
    //     }
    // 
    //     tree.push(entBranch);
    //   }
    // 
    //   return tree;
    // }
    // /** Truncates the string to the given length with an ellipses as suffix */
    // private ellipsis(maxLength: number, value: string): string {
    //   let output: string = value;
    //   if (output.length > maxLength) {
    //     let ellipsis = "...";  // Rather use the ellipsis character but String.fromCharCode(133) is returning a problematic character.
    //     output = output.slice(0, maxLength - 1 - ellipsis.length).concat(ellipsis);
    //   }
    //   return output;
    // }
    /**
     *
     * @param enterprise
     * @param environment
     * @param cabinet
     * @param asset
     * @param ctrInPod (Optional, defaults to the first one in the spec) The name of the running container (not the image) inside the pod (relevant only when there's more than one).
     * @param defaultValue
     * @returns
     */
    promptForReplica(replicas, ctrInPod, defaultValue) {
        var _a, _b, _c, _d, _e, _f;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let podName;
                // params:  enterprise: string, environment: string, cabinet: string, asset: string
                // // Retrieve replicas
                // this._ui.startSpinner(`Fetching ${asset} replicas in ${environment}/${cabinet}...`)
                // let reps = await this.genRelayClient.Call.assetStatus({ assetName: asset, cabinetName: cabinet, enterpriseCode: enterprise, environment: environment });
                // this._ui.stopSpinner((reps.successes) ? `${reps.successes.length} found.` : "failed.")
                // if (reps.error) throw reps.error;
                // if (reps.successes == undefined || reps.successes.length === 0) throw new Error(`No ${asset} replicas exist in cabinet ${environment}/${cabinet}. ${reps.message ?? ""}`);
                // 
                // let replicas = reps.successes[0].currentVersion.pods;   // <--- HEY!!! Relay shouldnt be exposing raw k8s contracts here - this shd be a codiac contract
                let choices = replicas.filter(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) !== undefined; })
                    .map(r => { var _a, _b, _c; return ({ name: `${(_a = r.metadata.name) !== null && _a !== void 0 ? _a : ""} (${(_b = r.status) === null || _b === void 0 ? void 0 : _b.phase})`, value: (_c = r.metadata.name) !== null && _c !== void 0 ? _c : "" }); });
                // Select a replica...
                if (choices.length === 0) {
                    this._ui.userMessage(`No replicas found.`);
                    podName = "unknown";
                    // return undefined;  // <--- this is what we should do here.
                }
                else if (choices.length === 1) {
                    podName = choices[0].value;
                    this._ui.userMessage(`1 replica found: ${this._styler.hilite(podName)}`);
                }
                else {
                    let keep = this.takeDefaults;
                    if (defaultValue && Boolean(choices.find(x => x.value === defaultValue)) && !this.takeDefaults) {
                        keep = yield this._ui.promptConfirm("keepReplica", `Replica: ${this._styler.hilite(defaultValue)} `);
                    }
                    if (keep && defaultValue !== undefined) {
                        podName = defaultValue;
                    }
                    else {
                        choices.push({ name: "** any **", value: CodiacConstants.CliConstants.ARGUMENT_VALUE_FOR_ANY });
                        podName = (yield this._ui.promptSelect("replica", "Replica...", choices, false, false)); // Assertion operator ok here - we're not allowing undefined options.
                    }
                }
                let replica = (podName === CodiacConstants.CliConstants.ARGUMENT_VALUE_FOR_ANY) ? replicas[0] : (replicas.find(r => { var _a; return ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.name) === podName; })); // Assertion ok: selection was already limited to this list.
                // Select the container inside...
                let containerName;
                if ((((_a = replica.spec) === null || _a === void 0 ? void 0 : _a.containers) == undefined) || (((_b = replica.spec) === null || _b === void 0 ? void 0 : _b.containers.length) === 0))
                    throw new Error("No containers are specified in that replica");
                if (!_.isEmpty(ctrInPod)) {
                    let found = replica.spec.containers.find(c => c.name === ctrInPod);
                    if (!found)
                        throw new Error(`Container [${ctrInPod}] not found in that replica`);
                    containerName = found.name;
                }
                else {
                    containerName = replica.spec.containers[0].name;
                    if (((_c = replica.spec) === null || _c === void 0 ? void 0 : _c.containers.length) > 1) {
                        // TODO: promptSelect from the list of containers
                        this._ui.userMessage(`${(_d = replica.spec) === null || _d === void 0 ? void 0 : _d.containers.length} containers in that replica; selected ${containerName}`);
                    }
                }
                let k8sCtr = {
                    namespace: (_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.namespace,
                    pod: (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.name,
                    container: containerName
                };
                return k8sCtr;
            }
            catch (err) {
                throw err;
            }
        });
    }
    renderSelectedContent(context, contentType, k8sEntities, contentOptions, replicas) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                switch (contentType) {
                    case (AssetContentType.logs):
                        if (context.replica == undefined)
                            throw new Error("No replica selected.");
                        if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
                            throw new Error("No replica selected.");
                        yield this.showLogs(context, contentOptions);
                        break;
                    case (AssetContentType.term):
                        if (context.replica == undefined)
                            throw new Error("No replica selected.");
                        if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
                            throw new Error("No replica selected.");
                        let termArgs = { tty: true, command: (_a = contentOptions === null || contentOptions === void 0 ? void 0 : contentOptions.terminalStartup) !== null && _a !== void 0 ? _a : DEFAULT_TERMINAL_STARTER };
                        yield this.runExec(context, termArgs, k8sEntities);
                        break;
                    case (AssetContentType.exec):
                        if (context.replica == undefined)
                            throw new Error("No replica selected.");
                        if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
                            throw new Error("No replica selected.");
                        let execArgs = contentOptions;
                        execArgs.tty = false; // and we want a run-once behavior so the ws closes after the command completes.
                        yield this.runExec(context, execArgs, k8sEntities);
                        break;
                    case (AssetContentType.config):
                        if (context.assetType != contracts_1.AssetTypesEnum.helm) {
                            if (context.replica == undefined)
                                throw new Error("No replica selected.");
                            if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
                                throw new Error("No replica selected.");
                        }
                        let cfgInput = contentOptions;
                        if (cfgInput.rootPathName != undefined) {
                            if (!cfgInput.rootPathName.startsWith("/"))
                                cfgInput.rootPathName = "/".concat(cfgInput.rootPathName);
                            let cfgExec = { tty: false, command: ["cat", cfgInput.rootPathName] };
                            yield this.runExec(context, cfgExec, k8sEntities);
                        }
                        else {
                            // These configs arent retrievable as files from the image;
                            // each type is unique and will need its own retrieval logic 
                            // eg: 
                            //   filestore  --> writes a volume to the k8s deployment/podspec
                            //   footprint  --> writes reslurces to the k8s deployment/podspec
                            //   probing    --> writes probe specs to the k8s deployment/podspec
                            //   label      --> writes meta labels to the k8s deployment/podspec
                            //   annotation --> writes meta annotations to the k8s deployment/podspec
                            //   helm       --> writes chart config to a k8s secret (I think... havent tried decrypting the release secret - or it may just be a hash.  Best to call the relay to use the Helm client)
                            this._ui.userMessage(`Viewing runtime configs of type: [${(_b = cfgInput.configType) !== null && _b !== void 0 ? _b : "(unspecified)"}] not supported yet.`);
                        }
                        break;
                    case (AssetContentType.env):
                        if (context.replica == undefined)
                            throw new Error("No replica selected.");
                        if (k8sEntities.pod == undefined || k8sEntities.container == undefined)
                            throw new Error("No replica selected.");
                        let envArgs = { tty: false, command: "env" };
                        yield this.runExec(context, envArgs, k8sEntities);
                        break;
                    case (AssetContentType.status):
                        // await this.watchEvents(context, k8sEntities.namespace, replicas);
                        yield this.watchStatus_NEW(context, k8sEntities.namespace);
                        // await this.watchStatus(context, k8sEntities.namespace, replicas);
                        // await this.watchReplicaSet(context, k8sEntities.namespace);
                        // await this.showStatus(context, k8sEntities.namespace, replicas);
                        break;
                    default:
                        this.logger.debug(`Content type ${contentType} is not yet supported.`, [context, contentType, contentOptions]);
                        this._ui.userMessage(`Content type ${contentType} is not yet supported.`);
                }
                return;
            }
            catch (err) {
                throw (err);
            }
        });
    }
    // COMMENTED OUT BC: Moved to K8sUtils
    // protected async getKubeConfig(context: AssetReplicaContext): Promise<k8s.KubeConfig> {
    //   // Retrieve cluster connection specs
    //   let res = await this.genRelayClient.Call.getClusterConnectionSpecs({
    //     enterprise: context.enterprise,
    //     environment: context.environment,
    //     cabinet: context.cabinet
    //   });
    //   if (res.error) throw res.error;
    //   if (res.output == undefined || _.isEmpty(res.output)) {
    //     this.log(`Failed loading cluster spec: ${res.message}.`);
    //     throw new Error(`Failed loading cluster spec: ${res.message}.`);
    //   }
    //   // Create the k8s client
    //   let k8sConfig = new KubeConfig();
    //   k8sConfig.loadFromString(res.output);
    //   return k8sConfig;
    // }
    // protected async getK8sClient(context: AssetReplicaContext, kube?: k8s.KubeConfig | undefined): Promise<k8s.CoreV1Api> {
    //   let k8sConfig = kube ?? (await this.getKubeConfig(context));
    //   let theirApi = k8sConfig.makeApiClient(k8s.CoreV1Api);
    //   return theirApi;
    // }
    /** Gets the cluster cnxn specs from the relay, then makes the k8s call from the cli.
     *
     * Throws any errors. */
    fetchReplicas(context, namespace, k8sClient) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let theirApi = k8sClient !== null && k8sClient !== void 0 ? k8sClient : yield this.k8sUtils.getK8sClient(context);
                // Fetch from the cluster
                let podResult = yield this.tryListNamespacedPods(theirApi, namespace, `${codiac_constants_1.CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`);
                let replicas = podResult.items;
                // let replicas = _.orderBy(podResult.body.items, p => p.metadata?.labels?.assetVersion, 'desc');  // NOTE: this isnt a semantic version sort
                try {
                    // Might need a semver.coerce() in here...
                    replicas = replicas.sort((a, b) => { var _a, _b, _c, _d, _e, _f; return semver.rcompare((_c = (_b = (_a = a.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : "", (_f = (_e = (_d = b.metadata) === null || _d === void 0 ? void 0 : _d.labels) === null || _e === void 0 ? void 0 : _e.assetVersion) !== null && _f !== void 0 ? _f : ""); }); // removes semvers so they can be sorted uniquely
                }
                catch (err) {
                    replicas = _.orderBy(replicas, p => { var _a, _b, _c; return (_c = (_b = (_a = p.metadata) === null || _a === void 0 ? void 0 : _a.labels) === null || _b === void 0 ? void 0 : _b.assetVersion) !== null && _c !== void 0 ? _c : ""; }); // TODO: we need this ALSO sorted by replica set (ie: name or labels["pod-template-hash"])
                }
                return replicas;
            }
            catch (err) {
                throw err;
            }
        });
    }
    // protected async watchEvents(context: AssetReplicaContext, namespace: string, replicas?: k8s.V1Pod[] | undefined): Promise<void> {
    //   // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
    //   let selector = `app=${context.asset}`;
    //   let creds = await this.getKubeConfig(context);
    //   let k8sClient = creds.makeApiClient(k8s.EventsV1Api);
    //   let watcher = new Watch(creds);
    //   watcher.watch(
    //     '/apis/events.k8s.io/v1/namespaces/{namespace}/events', 
    //   )
    //   let res = await k8sClient.listNamespacedEvent(namespace, undefined, undefined, undefined, undefined, selector,
    //     undefined, undefined, undefined, undefined, true, undefined);
    // }
    watchStatus_NEW(context, namespace, retry = 3) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let _retry = retry;
            let selector = `app=${context.asset}`;
            let kube = yield this.k8sUtils.getKubeConfig(context);
            let k8sClient = yield this.k8sUtils.getK8sClient(context);
            (0, log_update_wrapper_1.logUpdate)(`Watching ${this._styler.hilite(context.asset)} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
            log_update_wrapper_1.logUpdate.done();
            (0, log_update_wrapper_1.logUpdate)(`...empty...`);
            const watcher = new k8s.Watch(kube);
            const informer = new k8s.ListWatch(`/api/v1/namespaces/${namespace}/pods`, watcher, () => this.tryListNamespacedPods(k8sClient, namespace, selector));
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                informer.on('change', (obj) => {
                    let canvas = { table: "", curver: "" };
                    let replicas = informer.list(namespace);
                    if (replicas.length > 0) {
                        for (let pod of replicas) {
                            this.renderReplicaStatusRow(pod, canvas);
                        }
                    }
                    else {
                        canvas.table = "(no instances found)";
                    }
                    log_update_wrapper_1.logUpdate.clear();
                    (0, log_update_wrapper_1.logUpdate)(canvas.table);
                });
                informer.on('error', (err) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                    var _a;
                    const errorMessage = err instanceof Error ? err.message : (((_a = err.status) === null || _a === void 0 ? void 0 : _a.message) || "unknown error");
                    this.logger.debug(`Error occured with the watcher/informer:`, errorMessage);
                    if (_retry-- <= 0) {
                        yield informer.stop();
                        this.logger.debug(`Trying to restart informer, number of retries left: ${retry}`);
                        reject(Error("The connection has been terminated, you may want to restart."));
                        return;
                    }
                    setTimeout(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
                        yield informer.start();
                    }), 2000);
                }));
                yield informer.start();
            }));
        });
    }
    /** Wrapper for k8s client to handler exceptions (esp 401 and 403).
     *
     * Without this wrapper, the k8s client crashes the whole process with unhandled errors.
     */
    tryListNamespacedPods(k8sClient, namespace, selector) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let results = { items: [] };
            try {
                // results = await k8sClient.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, selector);
                results = yield k8sClient.listNamespacedPod({ namespace, labelSelector: selector });
            }
            catch (err) {
                this.logger.error("Error listing pods in namespace ".concat("[", namespace, "]", ": ", (_a = err.status) !== null && _a !== void 0 ? _a : "", " ", (_c = (_b = err.message) !== null && _b !== void 0 ? _b : err.reason) !== null && _c !== void 0 ? _c : ""));
            }
            finally {
                return results;
            }
        });
    }
    watchReplicaSet(context, namespace, replicaSets) {
        var _a, _b, _c, _d, _e, _f, _g;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let k8sConfig = (yield this.k8sUtils.getKubeConfig(context));
            let k8sClient = k8sConfig.makeApiClient(k8s.AppsV1Api);
            // let selector = `${CodiacLabels.LABEL_ASSET_NAME}=${context.asset}`;
            let selector = `app=${context.asset}`;
            let watch = true;
            do {
                let content = "";
                log_update_wrapper_1.logUpdate.clear();
                try {
                    let podResult = yield k8sClient.listNamespacedReplicaSet({ namespace, labelSelector: selector });
                    let output = podResult.items;
                    for (let item of output) {
                        if (item.status) {
                            content = content.concat(`${(_b = (_a = item.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed"}  ${(_c = item.status.availableReplicas) !== null && _c !== void 0 ? _c : 0}/${item.status.replicas}`, "\n");
                        }
                        else {
                            content = content.concat(`no status for ${(_e = (_d = item.metadata) === null || _d === void 0 ? void 0 : _d.name) !== null && _e !== void 0 ? _e : "unnamed"}`, "\n");
                        }
                    }
                }
                catch (err) {
                    content = content.concat(`Error ${(_f = err.name) !== null && _f !== void 0 ? _f : ""} ${(_g = err.message) !== null && _g !== void 0 ? _g : ""}`, "\n");
                }
                (0, log_update_wrapper_1.logUpdate)(content);
                yield this.unblockAndSleep(0.5);
            } while (watch);
        });
    }
    watchStatus(context, namespace, replicas) {
        var _a, _b, _c, _d, _e, _f, _g;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let watch = true;
            let k8sClient = yield this.k8sUtils.getK8sClient(context);
            let pods = replicas;
            let spinChars = ["|", "/", "-", "\\"];
            let spinIndex = -1;
            (0, log_update_wrapper_1.logUpdate)(`Status for ${context.asset} in ${context.environment}/${context.cabinet}... (ctrl-c to quit)`);
            log_update_wrapper_1.logUpdate.done();
            do {
                // await this.showStatus(context, namespace, pods, k8sClient);
                spinIndex++;
                if (spinIndex >= spinChars.length)
                    spinIndex = 0;
                let spinner = spinChars[spinIndex];
                // TODO: trap failures here and if status currently exists, render the error and leave the existing
                let table = "";
                try {
                    pods = pods !== null && pods !== void 0 ? pods : yield this.fetchReplicas(context, namespace, k8sClient);
                    if (pods && pods.length > 0) {
                        log_update_wrapper_1.logUpdate.clear();
                        let curver = ""; // current asset version being listed 
                        // let deployed = res.successes[0].currentVersion.deployed;
                        for (let replica of pods) {
                            let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
                            let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
                            let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
                            let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
                            // Version separator
                            if (assetVersion !== undefined && assetVersion !== curver) {
                                curver = assetVersion;
                                table = table.concat(`${spinner} ${assetVersion}`, "\n");
                            }
                            // Each replica
                            if (replica.status) {
                                let state = this.renderPodState(replica);
                                let condition = this.renderCondition(replica);
                                let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
                                table = table.concat(`  ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
                            }
                        }
                    }
                    else {
                        table = table.concat(`No running instances found.`);
                    }
                }
                catch (err) {
                    table = table.concat(`Error refreshing... ${(_g = err.message) !== null && _g !== void 0 ? _g : err.name}\n`);
                }
                (0, log_update_wrapper_1.logUpdate)(table);
                pods = undefined;
                yield this.unblockAndSleep(0.5);
            } while (watch);
        });
    }
    /** Mutates canvas */
    renderReplicaStatusRow(replica, canvas) {
        var _a, _b, _c, _d, _e, _f;
        let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
        let podHash = ((_c = replica.metadata) === null || _c === void 0 ? void 0 : _c.labels) ? (_d = replica.metadata) === null || _d === void 0 ? void 0 : _d.labels["pod-template-hash"] : undefined;
        let replicaId = podHash ? replicaName.slice(replicaName.indexOf(podHash)) : replicaName;
        let assetVersion = ((_e = replica.metadata) === null || _e === void 0 ? void 0 : _e.labels) ? (_f = replica.metadata) === null || _f === void 0 ? void 0 : _f.labels[codiac_constants_1.CodiacLabels.LABEL_ASSET_VERSION] : undefined;
        // Version separator
        if (assetVersion !== undefined && assetVersion !== canvas.curver) {
            canvas.curver = assetVersion;
            canvas.table = canvas.table.concat(`${assetVersion}`, "\n");
        }
        // Each replica
        if (replica.status) {
            let state = this.renderPodState(replica);
            let condition = this.renderCondition(replica);
            let restarts = (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) ? replica.status.containerStatuses[0].restartCount : 0;
            canvas.table = canvas.table.concat(`  ${replicaId}) ${state} ${condition} started (${replica.status.startTime}) ${restarts} restarts\n`); // , deployed (${deployed})`)
        }
    }
    renderCondition(replica) {
        var _a;
        let cond = "";
        if (replica.status) {
            if (((_a = replica.status) === null || _a === void 0 ? void 0 : _a.conditions) && replica.status.conditions.length > 0) {
                let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
                cond = latestCond.type;
                if (latestCond.reason) {
                    cond = cond.concat(" (", latestCond.reason, ")");
                }
                if (latestCond.message) {
                    // TODO: Revisit;  message is prob too much info to jam into a cli output line.
                    cond = cond.concat(" ('", latestCond.message, "')");
                }
                cond = cond.concat(` since (${latestCond.lastTransitionTime})`);
            }
        }
        return cond;
    }
    renderPodState(replica) {
        var _a, _b, _c, _d;
        let state = "[no status found]";
        if ((_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.deletionTimestamp) {
            state = "Terminating";
        }
        else if (replica.status) {
            state = "";
            // Pod phase
            if (replica.status.phase) {
                state = replica.status.phase;
            }
            if (replica.status.reason) {
                state = state.concat(" (", replica.status.reason, ")");
            }
            if (replica.status.message) {
                state = state.concat(" ('", replica.status.message, "')");
            }
            // container state
            if (replica.status.containerStatuses && replica.status.containerStatuses.length > 0) {
                let ctrStatus = replica.status.containerStatuses[0];
                // state = state.concat("  ", JSON.stringify(ctrStatus.state), "\n");
                if ((_b = ctrStatus.state) === null || _b === void 0 ? void 0 : _b.waiting) {
                    if (ctrStatus.state.waiting.reason) {
                        state = state.concat(" (", ctrStatus.state.waiting.reason, ")");
                    }
                    if (ctrStatus.state.waiting.message) {
                        state = state.concat(" ('", ctrStatus.state.waiting.message, "')");
                    }
                }
                else if ((_c = ctrStatus.state) === null || _c === void 0 ? void 0 : _c.terminated) {
                    if (ctrStatus.state.terminated.reason) {
                        state = state.concat(" (", ctrStatus.state.terminated.reason, ")");
                    }
                    if (ctrStatus.state.terminated.message) {
                        state = state.concat(" (", ctrStatus.state.terminated.message, ")");
                    }
                }
                else if ((_d = ctrStatus.state) === null || _d === void 0 ? void 0 : _d.running) {
                }
            }
        }
        return state;
    }
    unblockAndSleep(durationInSecs) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise(resolve => {
                setTimeout(() => resolve(), durationInSecs * 1000);
            });
        });
    }
    /** Fetches pods if not already provided. */
    showStatus(context, namespace, replicas, k8sApi) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let k8sClient = k8sApi !== null && k8sApi !== void 0 ? k8sApi : yield this.k8sUtils.getK8sClient(context);
                let pods = replicas !== null && replicas !== void 0 ? replicas : yield this.fetchReplicas(context, namespace, k8sClient);
                if (pods && pods.length > 0) {
                    // let deployed = res.successes[0].currentVersion.deployed;
                    console.log(`Status for ${context.asset} ${(pods.length > 0) ? " instances" : ""} running in ${context.environment}/${context.cabinet}`);
                    for (let replica of pods) {
                        let replicaName = (_b = (_a = replica.metadata) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : "unnamed";
                        if (((_c = replica.status) === null || _c === void 0 ? void 0 : _c.conditions) && replica.status.conditions.length > 0) {
                            let latestCond = _.orderBy(replica.status.conditions, x => x.lastTransitionTime, "desc")[0];
                            console.log(`${replicaName} ${latestCond.type} since (${latestCond.lastTransitionTime}) started (${replica.status.startTime}) ${replica.status.containerStatuses[0].restartCount} restarts`); // , deployed (${deployed})`)
                        }
                        else {
                            console.log("Condition not available"); // Thanks, nice and ambiguous; lets give them something actionable here instead.
                        }
                    }
                }
                else {
                    this._ui.userMessage(`No running instances found.`);
                }
                return;
            }
            catch (err) {
                throw err;
            }
        });
    }
    showLogs(context, logOptions) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                // SHOW LOGS
                let req = Object.assign(Object.assign({}, context), { logOptions: logOptions });
                let cnxnResult = yield this.genRelayClient.Call.getLogStreamSpecs(req);
                if (cnxnResult.error)
                    throw cnxnResult.error;
                if (cnxnResult.output == undefined)
                    throw new Error(`Failed  without error getting log stream connection specs.`);
                const logStream = new stream.PassThrough();
                logStream.on("data", (chunk) => {
                    // use write rather than console.log to prevent double line feed
                    process.stdout.write(chunk);
                });
                let streamer = new LogStreamer(this.logger);
                let requestOptions = cnxnResult.output;
                // Deserialize from strings into Buffers after their trip over the wire
                if (cnxnResult.output.ca)
                    requestOptions.ca = Buffer.from(cnxnResult.output.ca);
                else
                    this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a ca.`);
                if (cnxnResult.output.cert)
                    requestOptions.cert = Buffer.from(cnxnResult.output.cert);
                else
                    this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a cert.`);
                if (cnxnResult.output.key)
                    requestOptions.key = Buffer.from(cnxnResult.output.key);
                else
                    this.logger.warn(`Cluster connection specs retrieved for log streaming did not have a key.`);
                yield streamer.go(requestOptions, logStream); // shouldn't we be awaiting this?
                return;
            }
            catch (err) {
                throw err;
            }
        });
    }
    /**
     * @param context Fully qualified path, in terms of Codiac entities, to identify a single replica of an asset in a cabinet.
     * @param execArgs Parameters identifying the ultimate command to run and the console behavior.
     * @param K8sEntities The identifying names of the relevant kubernetes objects, corresponding to the asset replica context, that fully qualify the desired container. */
    runExec(context, execArgs, k8sEntities) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                let k8sCnxnResult = yield this.genRelayClient.Call.getClusterConnectionSpecs({ cabinet: context });
                if (k8sCnxnResult.error)
                    throw k8sCnxnResult.error;
                if (k8sCnxnResult.output === undefined || _.isEmpty(k8sCnxnResult.output))
                    throw new Error(`Retrieval of cluster connection spec failed without error.`);
                let spec = k8sCnxnResult.output;
                let kc = new k8s.KubeConfig();
                kc.loadFromString(spec);
                // ======================================================================================================
                // We have to resume here because the console keystrokes are not getting through, 
                // even though a POC running just the exec (without all the other ui code we're running)
                // doesnt have the input problem.
                // 
                // TODO:  Find out why we need this stdin resumed. 
                //        Most likely because it was piped into an spawned child process that has since ended.
                // 
                process.stdin.resume(); // Somehwere we probably lost track of a stdin
                // 
                // 
                // ======================================================================================================
                const exec = new k8s.Exec(kc);
                const ws = yield exec.exec(k8sEntities.namespace, k8sEntities.pod, k8sEntities.container, execArgs.command, process.stdout, process.stderr, process.stdin, execArgs.tty, (status) => {
                    // tslint:disable-next-line:no-console
                    // console.log("Exited with status:");
                    // // tslint:disable-next-line:no-console
                    this.logger.debug(`Executed terminal cmd. Status: ${status.status} ${status.reason}`, JSON.stringify(status, null, 2));
                });
                ws.onopen = function open() {
                    process.stdout.write("connected");
                };
                // ws.onclose = function close(evt) {
                //   // process.stdout.write("disconnected");
                //   process.exit(evt.code);
                //   return;
                // };
                ws.onclose = function close() {
                    // process.stdout.write("disconnected");
                    process.exit(1);
                    return;
                };
                ws.onmessage = this.routeK8sWebSocketMessage;
                //  function incoming(msg: any) {
                //   let buf = Buffer.from(msg.data);
                //   // The k8s client prefixes the buffer with the stream number at position 0...
                //   let streamNumBuf = buf.readInt8();
                //   let payload = buf.toString('utf8', 1);  // <-- start at pos 1 to skip the stream number.
                //   switch (streamNumBuf) {
                //     case WebSocketHandler.StdoutStream /* 1 */:
                //       process.stdout.write(payload);
                //       break;
                //     case WebSocketHandler.StderrStream /* 2 */:
                //       process.stderr.write(`ERROR: ` + payload);
                //       break;
                //     case WebSocketHandler.StatusStream /* 3 */:
                //       let k8sStatus = JSON.parse(payload) as V1Status;
                //       process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
                //       break;
                //     default:
                //       process.stderr.write(`feedback on ${streamNumBuf}`)
                //   }
                //   return;
                // };
                // This never gets hit.  Instead, onmessage gets hit with a message designated for stderr stream.
                ws.onerror = function error(err) {
                    process.stdout.write(`Error: ${err.message}`);
                    ws.close();
                };
                // Gotta do a process.exit(code) to give the control back.
                // THese dont fire
                // ws.once('exit', (code) => process.exit(code));
                // ws.once('end', (code) => process.stdout.write("end event fired"));
                return;
            }
            catch (err) {
                throw err;
            }
        });
    }
    /** Parses the stream number from the incoming message,
     * and writes the data to the designated target stream.
     *
     * (The k8s client prefixes the buffer with the stream number at position 0)
     */
    routeK8sWebSocketMessage(msg) {
        var _a;
        let buf = Buffer.from(msg.data);
        // The k8s client prefixes the buffer with the stream number at position 0...
        let streamNumBuf = buf.readInt8();
        let payload = buf.toString('utf8', 1); // <-- start at pos 1 to skip the stream number.
        switch (streamNumBuf) {
            case web_socket_handler_1.WebSocketHandler.StdoutStream /* 1 */:
                process.stdout.write(payload);
                break;
            case web_socket_handler_1.WebSocketHandler.StderrStream /* 2 */:
                process.stderr.write(`ERROR: ` + payload);
                break;
            case web_socket_handler_1.WebSocketHandler.StatusStream /* 3 */:
                let k8sStatus = JSON.parse(payload);
                if (((_a = k8sStatus.status) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "failure") {
                    if (k8sStatus.reason !== "NonZeroExitCode") {
                        process.stdout.write(`STATUS: ${k8sStatus.status}: ${k8sStatus.message}`);
                    }
                }
                break;
            default:
                process.stderr.write(`feedback on ${streamNumBuf}`);
        }
        return;
    }
}
exports.default = AssetView;
AssetView.description = 'Renders a selected type of content for an asset';
AssetView.aliases = ['asset:monitor', "asset:mon", "asset:get"];
AssetView.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    enterprise: core_1.Flags.string({ char: 'e', description: 'The name of the enterprise containing the asset being viewed.' }),
    asset: core_1.Flags.string({ char: 'a', description: 'The name of the asset to view.' }),
    environment: core_1.Flags.string({ char: 'n', description: 'The name of the environment in which the cabinet resides.' }),
    cabinet: core_1.Flags.string({ char: 'c', description: 'The name of the cabinet from which the content is to be drawn.' }),
    replica: core_1.Flags.string({ char: 'r', description: `The name of one of the asset instances currently running in the cabinet. Set to "${CodiacConstants.CliConstants.ARGUMENT_VALUE_FOR_ANY}" to select the first available replica without prompting for one.` }),
    type: core_1.Flags.string({ char: 't', options: [...Object.keys(AssetContentType)], description: 'The type of content to retrieve.' }),
    terminal: core_1.Flags.string({ options: ["bash", "sh"], description: 'Command used to start the terminal (defaults to "bash")' }),
    logsFollow: core_1.Flags.boolean({ char: 'f', default: false, description: '(requires type=logs) Follow (aka watch, tail, stream) the output.' }),
    logsTail: core_1.Flags.integer({ char: 'l', default: 10, description: '(requires type=logs) Lines of recent logs to include in the output.  Enter -1 to include the entire log history stored in the container.' }),
    configFile: core_1.Flags.string({ char: 'F', description: '(requires type=config) The root pathname to the config file to fetch.' }),
    configType: core_1.Flags.string({ char: 'T', exclusive: ["file"], options: Object.keys(codiac_domain_1.SpecialConfigTypesEnum), description: 'Filters for the settings types that do not land in a config file (such as... env: OS environment variables, footprint: container footprint specs, helm: helm chart settings, label: container meta labels, annotation: container platform key-value pairs).' }),
    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.' }),
    "take-defaults": core_1.Flags.boolean({ exclusive: ["silent"], description: "Prevents prompting for confirmation on parameters that were passed in or were set to default values." })
    // tty: Flags.boolean({ char: 'i', default: false, description: '(requires type=exec) Specifies an interactive console session.' })
};
AssetView.strict = false; // disables argument validation so we can support variable-length arguments.
AssetView.args = {
    cmd: core_1.Args.string({ description: '(requires type=exec) command and its space-separated arguments to run in the target replica.' })
};
class ExecArgs {
    constructor(command, tty = true) {
        this.command = command;
        this.tty = tty;
    }
}
exports.ExecArgs = ExecArgs;
class ConfigFileArgs {
    constructor(rootPathName, configType) {
        this.rootPathName = rootPathName;
        this.configType = configType;
    }
}
exports.ConfigFileArgs = ConfigFileArgs;
class TermArgs {
    /**
     *
     * @param terminalStartup The type of terminal to open.  This command may change depending on what terminal or command shell types are available in the image.
     */
    constructor(terminalStartup) {
        this.terminalStartup = terminalStartup;
    }
}
exports.TermArgs = TermArgs;
/** Idnetifies a container, in a pod, in a namespace, in a cluster. */
class K8sContainerRef {
    constructor(namespace, podName, 
    /** This should be optional. When there's only one container in a pod,
     * we should be able to derive this from the pod spec. */
    containerName) {
        this.namespace = namespace;
        this.podName = podName;
        this.containerName = containerName;
    }
}
exports.K8sContainerRef = K8sContainerRef;
class LogStreamer {
    constructor(logger) {
        this.logger = logger;
    }
    go(requestOptions, stream) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => {
                const req = request(requestOptions, (error, response, body) => {
                    if (error) {
                        reject(error);
                    }
                    else if (response.statusCode !== 200) {
                        this.logger.detail(`Error connecting to log stream`, body);
                        let details;
                        try {
                            const k8sStatus = JSON.parse(body);
                            details = `${k8sStatus.status}${k8sStatus.reason ? " (" + k8sStatus.reason + ")" : ""} ${k8sStatus.message}`;
                        }
                        catch (_a) {
                            details = "See cli log for details.";
                        }
                        reject(new Error(`Error connecting to log stream. ${details}`));
                    }
                }).on('response', (response) => {
                    if (response.statusCode === 200) {
                        req.pipe(stream);
                        resolve(req);
                    }
                }).on('error', (err) => {
                    var _a, _b;
                    reject(new Error(`Error streaming logs. ${(_a = err.name) !== null && _a !== void 0 ? _a : ""} ${(_b = err.message) !== null && _b !== void 0 ? _b : "no details available."}`));
                });
            });
        });
    }
}
exports.LogStreamer = LogStreamer;
//# sourceMappingURL=view.js.map