"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const contracts_1 = require("../../apis/codiac-api/contracts");
const command_base_exec_1 = require("../../command-base-exec");
const codiac_constants_1 = require("../../codiac-constants");
class EnvAdd extends command_base_exec_1.CommandBaseExec {
    captureArgs() {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(EnvAdd);
            let partial = {};
            // --enterprise (char 'n') serves dual purpose: enterprise scope AND enterprise context
            if (flags.enterprise)
                partial.enterprise = flags.enterprise;
            if ((_a = args.setting) !== null && _a !== void 0 ? _a : flags.setting)
                partial.setting = (_b = args.setting) !== null && _b !== void 0 ? _b : flags.setting;
            if (flags.value)
                partial.value = flags.value;
            return [partial, false];
        });
    }
    buildCandidate_silently(partial, rootMap) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { flags } = yield this.parse(EnvAdd);
            if (!partial.setting)
                throw new Error("Setting name (--setting or -s) is required in silent mode.");
            if (!partial.value)
                throw new Error("Setting value (--value or -v) is required in silent mode.");
            const ent = rootMap.enterprises.find(e => e.name === partial.enterprise);
            if (!ent)
                throw new Error(`Enterprise "${partial.enterprise}" not found.`);
            const aCntx = yield this.establishAssetContext(ent, true);
            const assetName = aCntx[0];
            let scopeLevel;
            let scopeName = partial.enterprise;
            if (flags.enterprise) {
                scopeLevel = contracts_1.ScopeLevel.enterprise;
                scopeName = flags.enterprise;
            }
            else if (flags.environment) {
                scopeLevel = contracts_1.ScopeLevel.environment;
                scopeName = flags.environment;
            }
            else if (flags.cabinet) {
                scopeLevel = contracts_1.ScopeLevel.cabinet;
                scopeName = flags.cabinet;
            }
            return { enterprise: partial.enterprise, assetName, setting: partial.setting, value: partial.value, scopeLevel, scopeName };
        });
    }
    buildCandidate_interactively(partial, rootMap, takeDefaults) {
        var _a, _b, _c;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { args, flags } = yield this.parse(EnvAdd);
            this._ops.getConfigRoot(); // Verify that it's being called from within a defined project.
            const ent = rootMap.enterprises.find(e => e.name === partial.enterprise);
            if (!ent)
                throw new Error(`Enterprise "${partial.enterprise}" not found.`);
            const aCntx = yield this.establishAssetContext(ent, true);
            const assetName = aCntx[0];
            // Prompt for setting name
            let setting = (_a = partial.setting) !== null && _a !== void 0 ? _a : ((_c = (_b = args.setting) !== null && _b !== void 0 ? _b : flags.setting) !== null && _c !== void 0 ? _c : "");
            if (!setting) {
                setting = (yield this._ui.prompt("settingName", "Name of setting: ", true));
            }
            // Prompt for setting value
            let val;
            if (partial.value) {
                val = partial.value;
            }
            else {
                val = (yield this._ui.prompt('settingValue', `Value for ${setting}: `, true));
            }
            // Determine scope level
            let scopeLevel;
            let scopeName = partial.enterprise;
            if (flags.enterprise) {
                scopeLevel = contracts_1.ScopeLevel.enterprise;
                scopeName = flags.enterprise;
            }
            else if (flags.environment) {
                scopeLevel = contracts_1.ScopeLevel.environment;
                scopeName = flags.environment;
            }
            else if (flags.cabinet) {
                scopeLevel = contracts_1.ScopeLevel.cabinet;
                scopeName = flags.cabinet;
            }
            else {
                const choices = [
                    { name: `Anywhere in the ${this._styler.bold(partial.enterprise)} 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" }
                ];
                const selected = yield this._ui.promptSelect("level", "Scope: Where should this value apply? ", choices);
                if (selected && selected !== "none")
                    scopeLevel = contracts_1.ScopeLevel[selected];
            }
            // Prompt for scope name (if applicable)
            if (scopeLevel && !scopeName) {
                let scopeChoices = [];
                if (scopeLevel === contracts_1.ScopeLevel.environment) {
                    const resultenvs = yield this._codiacApi.Environment.tryReadMany({ all: true }, { projection: { pathsIncluded: ["code"], pathsExcluded: [] } });
                    if (resultenvs.error)
                        throw resultenvs.error;
                    if (resultenvs.output)
                        scopeChoices = resultenvs.output.map(e => ({ name: e.code, value: e.code }));
                }
                else if (scopeLevel === contracts_1.ScopeLevel.cabinet) {
                    const resultCabs = yield this._codiacApi.Cabinet.tryReadMany({ enterpriseCode: partial.enterprise }, { projection: { pathsIncluded: ["name"], pathsExcluded: [] } });
                    if (resultCabs.error)
                        throw resultCabs.error;
                    if (resultCabs.output)
                        scopeChoices = resultCabs.output.map(c => ({ name: c.name, value: c.name }));
                }
                if (scopeChoices.length > 0) {
                    const selectedScope = yield this._ui.promptSelect("scopeName", `Which ${scopeLevel}? `, scopeChoices, true);
                    if (selectedScope)
                        scopeName = selectedScope;
                }
            }
            return { enterprise: partial.enterprise, assetName, setting, value: val, scopeLevel, scopeName };
        });
    }
    buildCommandString(candidate, cmd) {
        cmd.push("-s", candidate.setting);
        cmd.push("-v", candidate.value);
        if (candidate.scopeLevel === contracts_1.ScopeLevel.enterprise && candidate.scopeName)
            cmd.push("-n", candidate.scopeName);
        else if (candidate.scopeLevel === contracts_1.ScopeLevel.environment && candidate.scopeName)
            cmd.push("-e", candidate.scopeName);
        else if (candidate.scopeLevel === contracts_1.ScopeLevel.cabinet && candidate.scopeName)
            cmd.push("-c", candidate.scopeName);
        cmd.push("--silent");
        return cmd;
    }
    executeTask(candidate) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (candidate.scopeLevel && candidate.scopeName) {
                yield this.writeSetting_Api(candidate.enterprise, candidate.assetName, codiac_constants_1.ENV_CODE_NAME, candidate.setting, candidate.scopeLevel, candidate.scopeName, candidate.value);
            }
            else {
                this.writeSettingEnv_local(candidate.setting, candidate.value);
            }
            this.log(`Applied environment setting "${candidate.setting}" = "${candidate.value}"`);
        });
    }
    writeSetting_Api(enterprise, assetName, configName, setting, scopeLevel, scopeName, val) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const settingObj = Object.assign({ setting, value: val, targetFile: configName, asset: assetName, enterprise, scope: scopeLevel, target: scopeName }, this.createAuditable());
            const crit = {
                enterprise: settingObj.enterprise,
                asset: settingObj.asset,
                targetFile: settingObj.targetFile,
                scope: scopeLevel,
                target: scopeName,
                setting: settingObj.setting
            };
            const 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) {
                throw resultSetting.error;
            }
            else {
                throw new Error(`Failed without error to save setting [${settingObj.setting}]: ${(_a = resultSetting.message) !== null && _a !== void 0 ? _a : ""}`);
            }
        });
    }
    writeSettingEnv_local(setting, value) {
        console.log(`TODO:  Persist env vars locally:  ${setting}=${value}`);
    }
    /** 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 at a given scope (enterprise, environment, or cabinet).';
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 data to be applied as the setting value." }),
    enterprise: core_1.Flags.string({ char: 'n', exclusive: ["environment", "cabinet"], description: 'The name of the enterprise scope to which this value is to apply.' }),
    environment: core_1.Flags.string({ char: 'e', exclusive: ["enterprise", "cabinet"], description: 'The name of the environment scope to which this value is to apply.' }),
    cabinet: core_1.Flags.string({ char: 'c', exclusive: ["enterprise", "environment"], description: 'The name of the cabinet scope to which this value is to apply.' }),
    silent: core_1.Flags.boolean({ exclusive: ["echo", "to-script"], description: 'Executes without any user interaction; fails on missing or invalid arguments.' }),
    echo: core_1.Flags.boolean({ exclusive: ["to-script", "silent"], description: 'Renders the equivalent non-interactive command for future use before executing.' }),
    "to-script": core_1.Flags.boolean({ exclusive: ["echo", "silent"], description: 'Renders the equivalent non-interactive command without executing it.' }),
};
EnvAdd.args = {
    setting: core_1.Args.string({ description: 'The name of the environment variable to add.' })
};
EnvAdd.examples = [
    { description: "Add a setting interactively.", command: "<%= config.bin %> <%= command.id %>" },
    { description: "Add a setting at enterprise scope.", command: "<%= config.bin %> <%= command.id %> -s MY_VAR -v myValue -n myEnterprise --silent" },
    { description: "Add a setting at environment scope.", command: "<%= config.bin %> <%= command.id %> -s MY_VAR -v myValue -e production --silent" },
    { description: "Add a setting at cabinet scope.", command: "<%= config.bin %> <%= command.id %> -s MY_VAR -v myValue -c dev --silent" },
    { description: "Renders the equivalent silent command without executing.", command: "<%= config.bin %> <%= command.id %> -s MY_VAR -v myValue -n myEnterprise --to-script" },
];
//# sourceMappingURL=add.js.map