"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const _ = require("lodash");
const contracts_1 = require("../../apis/codiac-api/contracts");
const command_base_enterprise_1 = require("../../command-base-enterprise");
const codiac_constants_1 = require("../../codiac-constants");
class EnvAdd extends command_base_enterprise_1.CommandBaseEnterprise {
    run() {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                this.bootstrap();
                const { args, flags } = yield this.parse(EnvAdd);
                this._ops.getConfigRoot(); // Verify that it's being called from within a defined project.
                this._userCntx = yield this.establishTenantContext(this._userCntx);
                let rootMap = yield this.getRootMap();
                const interactionMode = this.getInteractionMode(flags.silent, flags.echo, flags['to-script']);
                let enterprise = (yield this.establishEnterpriseContext(rootMap, flags.enterprise, interactionMode)).enterprise;
                _.remove(rootMap.enterprises, e => e.name != enterprise.name); // trim down to match legacy conditions
                let enterpriseCode = enterprise.name;
                let aCntx = yield this.establishAssetContext(enterprise, true);
                // let cab = await this.establishCabinet(flags.cabinet, true);
                let configName = codiac_constants_1.ENV_CODE_NAME;
                // 1 Get the list of available built in system settings
                // stub:
                this._envConfig = {};
                let avails = yield this.getAvailableSettings();
                // Prompt for setting if reqd
                let setting = (_a = args.setting) !== null && _a !== void 0 ? _a : flags.setting;
                if (!setting) {
                    // let result = await inquirer.prompt({ type: 'list', name: 'setting', message: 'Setting to add:', choices: avails});
                    setting = (yield this._ui.prompt("settingName", "Name of setting: ", true)); // TODO:  Stop returning undefined when required is true.
                }
                // this.log(result.setting);
                // PROMPT FOR VALUE (if reqd)
                let val;
                if (flags.value) {
                    val = flags.value;
                }
                else {
                    // TODO: this current value needs to support the scoped value set
                    let currentValue = (this._envConfig) ? this._envConfig[setting] : undefined;
                    let response = yield this._ui.prompt('settingValue', `Value for ${setting}: `, true, currentValue);
                    val = response;
                }
                let level;
                let scopeName;
                if (flags.enterprise || flags.environment || flags.cabinet) {
                    // WRITE SCOPED TO THE API
                    level = contracts_1.ScopeLevel.enterprise;
                    scopeName = enterpriseCode;
                    if (flags.enterprise) {
                        level = contracts_1.ScopeLevel.enterprise;
                        scopeName = flags.enterprise;
                        // TODO: Validate that the enterprise exists
                    }
                    else if (flags.environment) {
                        level = contracts_1.ScopeLevel.environment;
                        scopeName = flags.environment;
                        // TODO: Validate
                    }
                    else if (flags.cabinet) {
                        level = contracts_1.ScopeLevel.cabinet;
                        scopeName = flags.cabinet;
                        // TODO: Validate
                    }
                }
                // PROMPT FOR SCOPE LEVEL
                if (!level) {
                    let choices = [
                        { name: `Anywhere in the ${this._styler.bold(enterpriseCode)} enterprise`, value: contracts_1.ScopeLevel.enterprise },
                        { name: `A specific ${this._styler.bold("environment")}`, value: contracts_1.ScopeLevel.environment },
                        { name: `A specific ${this._styler.bold("cabinet")}`, value: contracts_1.ScopeLevel.cabinet },
                        { name: `Just when running ${this._styler.bold("local")}`, value: "none" }
                    ];
                    let selected = yield this._ui.promptSelect("level", "Scope: Where should this value apply? ", choices);
                    if (selected && selected != "none")
                        level = contracts_1.ScopeLevel[selected];
                }
                // PROMPT FOR SCOPE
                if (level && !scopeName) {
                    let choices = [];
                    switch (level) {
                        case contracts_1.ScopeLevel.enterprise:
                            scopeName = enterpriseCode;
                            break;
                        case contracts_1.ScopeLevel.environment:
                            let resultenvs = yield this._codiacApi.Environment.tryReadMany({ all: true }, { projection: { pathsIncluded: ["code"], pathsExcluded: [] } });
                            if (resultenvs.error)
                                throw resultenvs.error;
                            if (resultenvs.output) {
                                choices = resultenvs.output.map(e => { return { name: e.code, value: e.code }; });
                            }
                            break;
                        case contracts_1.ScopeLevel.cabinet:
                            let resultCabs = yield this._codiacApi.Cabinet.tryReadMany({ enterpriseCode: enterpriseCode }, { projection: { pathsIncluded: ["name"], pathsExcluded: [] } });
                            if (resultCabs.error)
                                throw resultCabs.error;
                            if (resultCabs.output) {
                                choices = resultCabs.output.map(c => { return { name: c.name, value: c.name }; });
                            }
                            break;
                    }
                    if (!scopeName && choices) {
                        let selected = yield this._ui.promptSelect("scopeName", `Which ${level}? `, choices, true);
                        scopeName = selected;
                    }
                }
                if (level && scopeName) {
                    let assetName = aCntx[0];
                    this.writeSetting_Api(enterpriseCode, assetName, configName, setting, level, scopeName, val);
                }
                else {
                    // WRITE UNSCOPED TO LOCAL
                    this.writeSettingEnv_local(setting, val);
                }
                this.log(`Applied environment setting "${setting}" = "${val}"`);
                return;
            }
            catch (err) {
                this.handleError(err);
                return;
            }
            finally {
                yield this.closeConnections();
            }
        });
    }
    writeSetting_Api(enterprise, assetName, configName, setting, scopeLevel, scopeName, val) {
        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 cntx = await this.loadCodiacContext();
                    // let cntx = await this.establishTenantContext(this._userCntx);
                    let cntx = this._userCntx;
                    // TODO:  Look to enterprise context instead.
                    // let enterprise = /* this._cfg.enterprise || */ this._projCfg.tenantCode;
                    // TODO: Look to asset context instead - and if none, fail and call for "$ cod asset:set"
                    // let assetName = this._projCfg.name;  // this needs to be taken from an image definition.  (AssetBinding[] needs to be added to each ImageExport)
                    // NOTE:  We could bind a config to an image name,
                    //        and then allow for an Asset scope to set values on it...
                    let settingObj = Object.assign({ setting: setting, value: val, targetFile: configName, asset: assetName, enterprise: enterprise, scope: scopeLevel, target: scopeName }, this.createAuditable());
                    let crit = {
                        enterprise: settingObj.enterprise,
                        asset: settingObj.asset,
                        targetFile: settingObj.targetFile,
                        scope: scopeLevel,
                        target: scopeName,
                        setting: settingObj.setting
                    };
                    // TODO:  Replace this with an upsert based on:  enterprise, asset, configName, scopeLevel, scopeName, and setting
                    let check = yield this._codiacApi.ScopedSetting.tryReadMany(crit);
                    let resultSetting;
                    if (check.success && check.output && check.output.length > 0) {
                        settingObj.id = check.output[0].id;
                        resultSetting = yield this._codiacApi.ScopedSetting.tryUpdate(settingObj);
                    }
                    else {
                        resultSetting = yield this._codiacApi.ScopedSetting.tryCreate(settingObj);
                    }
                    if (resultSetting.success) {
                        this.logger.notice(`Successfully saved setting [${settingObj.setting}] for ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                        this._ui.userMessage(`Successfully saved setting [${settingObj.setting}] for ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                    }
                    else if (resultSetting.error) {
                        this.logger.error(`Error saving setting [${settingObj.setting}]: ${resultSetting.message || ""}; ${resultSetting.error.message || resultSetting.error.stack}; For ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                        this._ui.userMessage(`Error saving setting [${settingObj.setting}]: ${resultSetting.message || ""}; ${resultSetting.error.message || resultSetting.error.stack}; For ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                    }
                    else {
                        this.logger.warn(`Failed without error to save setting [${settingObj.setting}]: ${resultSetting.message || ""}; For ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                        this._ui.userMessage(`Failed without error to save setting [${settingObj.setting}]: ${resultSetting.message || ""}; For ${settingObj.scope} [${settingObj.target}] in ${settingObj.enterprise}/${settingObj.asset} config [${settingObj.targetFile}]`);
                    }
                    resolve();
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    writeSettingEnv_local(setting, value) {
        // Consider writing env vars to the ImageExport def in codiac.json
        // We'll need them when we run the image.
        console.log(`TODO:  Persist env vars locally:  ${setting}=${value}`);
        // Write the available setting
        // if (!this._appConfig) {
        //   this._appConfig = {};
        // }
        // _.set(this._appConfig, setting, value);
        // // this._appConfig[setting] = val.settingValue;
        // this._ops.writeConfig(this._appConfig);
    }
    /** Retrieves the list of settings from the env schema that are not yet explicitly declared. */
    getAvailableSettings() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return [];
        });
    }
}
exports.default = EnvAdd;
EnvAdd.description = 'Adds a key value pair to the app config';
// static aliases = ['env:add']
EnvAdd.flags = {
    help: core_1.Flags.help({ char: 'h' }),
    setting: core_1.Flags.string({ char: 's', required: false, description: "The name of the environment variable to add." }),
    value: core_1.Flags.string({ char: 'v', required: false, description: "The actual concrete data to be applied as the setting value." }),
    enterprise: core_1.Flags.string({ char: 'n', exclusive: ["environment", "cabinet"], description: 'The name of the enterprise to which this value is to apply.' }),
    environment: core_1.Flags.string({ char: 'e', exclusive: ["enterprise", "cabinet"], description: 'The name of the environment to which this value is to apply.' }),
    cabinet: core_1.Flags.string({ char: 'c', exclusive: ["enterprise", "environment"], description: 'The name of the cabinet to which this value is to apply.' })
};
EnvAdd.args = {
    setting: core_1.Args.string({ description: 'The name of the environment variable to add' })
};
//# sourceMappingURL=add.js.map