"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PROMPT_ME_DESIGNATOR = void 0;
const tslib_1 = require("tslib");
require("reflect-metadata");
const core_1 = require("@oclif/core");
const inquirer = require("inquirer");
const _ = require("lodash");
//const autocomplete = require("inquirer-autocomplete-prompt");
const fuzzy = require("fuzzy");
const command_base_enterprise_1 = require("../../command-base-enterprise");
let assetVersions = [];
/** 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 = "?";
class AssetRecycle extends command_base_enterprise_1.CommandBaseEnterprise {
    run() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
                var _a;
                try {
                    this.bootstrap();
                    const { args, flags } = yield this.parse(AssetRecycle);
                    (_a = this._relayContainer) === null || _a === void 0 ? void 0 : _a.ready$.subscribe(() => tslib_1.__awaiter(this, void 0, void 0, function* () {
                        var _b;
                        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.enterpriseCode, interactionMode)).enterprise;
                        _.remove(rootMap.enterprises, e => e.name != enterprise.name); // trim down to match legacy conditions
                        let enterpriseCode = enterprise.name;
                        // Select the asset(s) to deploy
                        let assetVersions;
                        if (flags.asset == exports.PROMPT_ME_DESIGNATOR) {
                            let asset = yield this.promptForAsset(enterpriseCode);
                            // let selected = await this.promptForVersion(enterpriseCode, asset, flags.version);
                            assetVersions = [{ a: asset.name }];
                        }
                        else if (flags.asset) {
                            let asset = yield this.promptForAsset(enterpriseCode, flags.asset);
                            // let selected = await this.promptForVersion(enterpriseCode, asset, flags.version);
                            assetVersions = [{ a: asset.name }];
                            // if (!flags.version || flags.version == PROMPT_ME_DESIGNATOR) {
                            // }
                        }
                        else {
                            // Update sync codiac with what we've got here in the project.
                            let requestedAssets = yield this.establishAssetContext(enterprise, flags.silent);
                            assetVersions = requestedAssets.map(a => { return { a: a }; });
                            // let versions = await this.declareAssetVersions(requestedAssets, enterpriseCode);
                            // // We've updated Codiac.  Now trigger the deploy.
                            // assetVersions = requestedAssets.map(a => {
                            //   let version = versions.find(v => v.assetName == a);
                            //   return { a: a, v: version ? version.assetVersion : undefined };
                            // });
                        }
                        let cab;
                        [cab] = yield this.rootMapUtils.promptForCabinet(enterpriseCode, rootMap, flags.cabinetName, false, undefined);
                        // let cabinet = await this.establishCabinet(flags.cabinetName);
                        let cabCntx = { enterprise: cab.enterprise, environment: cab.environment, cabinet: cab.name };
                        // Get the clusterdef so we can get cloud pvd creds
                        let cluster = (_b = cab.cluster) !== null && _b !== void 0 ? _b : ((rootMap.clusters.length === 1) ? rootMap.clusters[0].name : undefined); // fall back to the one and only.
                        if (cluster === undefined) {
                            this.logger.warn(`Cannot confirm cloud provider credentials: cabinet has no cluster specified. Process will rely on cached credentials.`);
                            // throw new Error(`Cannot determine cloud provider: cabinet has no cluster specified.`);
                        }
                        else {
                            yield this.establishCloudProviderCreds(rootMap, cluster);
                        }
                        let assets = {
                            enterpriseCode: cabCntx.enterprise,
                            environment: cabCntx.environment,
                            cabinetName: cabCntx.cabinet,
                            assetNames: assetVersions.map(a => a.a)
                        };
                        this._ui.startSpinner(`Recycling assets in ${assets.cabinetName}...`);
                        // let result = await this.relayClient.recycleAssets(assets);
                        let result = yield this.genRelayClient.Call.postExecuteRecycleAssets(assets);
                        this._ui.stopSpinner((result.success === true) ? "SUCCESS" : (result.error) ? "ERROR" : "FAILED");
                        if (result.error) {
                            this.logger.error(`Error recycling assets in ${assets.cabinetName}: ${result.message}`, result.error);
                            this._ui.userMessage(`Error recycling assets in ${assets.cabinetName}: ${result.message}`);
                        }
                        else if (result.success) {
                            this.logger.notice(`Recycled assets in ${assets.cabinetName}`);
                            // this._ui.userMessage(`Recycled assets in ${assets.cabinetName}`);  // The spinner is enough for the user message here.
                        }
                        else {
                            this.logger.warn(`Failed recycling assets in ${assets.cabinetName}: ${result.message}`, result);
                            this._ui.userMessage(`Failed recycling assets in ${assets.cabinetName}: ${result.message}`);
                        }
                        resolve();
                    }));
                }
                catch (err) {
                    this.handleError(err);
                    reject(err);
                }
                finally {
                    yield this.closeConnections();
                }
            }));
        });
    }
    promptForAsset(enterprise, assetSearch) {
        return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                // let ecrit = new EnterpriseCriteria();
                // ecrit.code = new StringFilter();
                // ecrit.code.$eq = enterprise;
                let ecrit = { code: enterprise };
                let readResult = yield this._codiacApi.Enterprise.tryReadMany(ecrit /* { code: { $eq: enterprise } }  */);
                if (!readResult.output || readResult.output.length == 0) {
                    throw new Error(`Could not find enterprise [${enterprise}].`);
                }
                else if (!readResult.output[0].assets || readResult.output[0].assets.length == 0) {
                    throw new Error(`The current enterprise [${enterprise}] has no assets defined.`);
                }
                // console.log(`${readResult.output[0].assets.length} assets found`)
                // Select from assets in the current enterprise
                let assets = readResult.output[0].assets;
                if (assetSearch && assetSearch != exports.PROMPT_ME_DESIGNATOR) {
                    assets = assets.filter(a => a.name.startsWith(assetSearch));
                }
                // console.log(`${assets.length} assets found`)
                let assSelect = yield inquirer.prompt({ type: 'list', name: 'asset', message: 'Select an Asset:', choices: assets.map(a => a.name) });
                let selected = assets.find(a => a.name == assSelect.asset);
                if (!selected)
                    throw new Error(`User failed to select a valid asset to deploy.`);
                resolve(selected);
            }
            catch (err) {
                reject(err);
            }
        }));
    }
    searchVersions(answers, input) {
        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 {
                    // Whatever voodoo they're doing inside the autocomplete plugin,
                    // they're redefining "this", so we cant use it here.
                    // Great, we'll just HACK UP a fucking module scoped variable to hold onto the goddamn list then.
                    // let vers = this.getVersions();
                    input = input || "";
                    setTimeout(() => {
                        let options = { extract: (ver) => { return ver.value; } };
                        let results = fuzzy.filter(input, assetVersions, options);
                        let filtered = results.map((fr) => fr.original);
                        resolve(filtered);
                    }, _.random(30, 500)); // why a random number?
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
}
exports.default = AssetRecycle;
AssetRecycle.description = 'Deploys a given asset to a given cabinet.  Defaults to current version.';
AssetRecycle.dependsOn = ["enterpriseCode", "cabinetName"];
AssetRecycle.flags = {
    // ...commandBase.globalFlags,
    help: core_1.Flags.help({ char: 'h' }),
    enterpriseCode: core_1.Flags.string({ char: 'e', required: false, description: `Code (name) of the enterprise to deploy` }),
    cabinetName: core_1.Flags.string({ char: 'c', required: false, description: `Target cabinet name you want deploy` }),
    asset: core_1.Flags.string({ char: 'a', required: false, description: `Search string for the name of the asset to deploy (use ${exports.PROMPT_ME_DESIGNATOR} to be prompted).` }),
    version: core_1.Flags.string({ char: 'v', required: false, description: `Search string for the version of the asset to deploy  (use ${exports.PROMPT_ME_DESIGNATOR} to be prompted).` }),
    silent: core_1.Flags.boolean({ char: 'y', dependsOn: AssetRecycle.dependsOn, required: false, description: `(Optional: defaults to false) Prevents confirmations of user-values that are remembered from prior runs. Requires: ${AssetRecycle.dependsOn}` })
};
AssetRecycle.args = {};
// type FuzzyResult = {
//     /** The rendered string (eg: '<b>lah'). */
//     string: string,
//     /** The index of the element in `arr` (eg: 2). */
//     index: number,
//     /** The original element in `arr`. */
//     original: 'blah'
// }
//# sourceMappingURL=recycle.js.map