"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PromptSelectFuzzy = void 0;
const tslib_1 = require("tslib");
const codiac_common_1 = require("@codiac.io/codiac-common");
const inversify_1 = require("inversify");
const autocomplete = require("inquirer-autocomplete-prompt");
const inquirer = require("inquirer");
const fuzzy = require("fuzzy");
const INTERFACES_CLI_1 = require("../ops/INTERFACES_CLI");
/** Has to be module-scoped bc the autocomplete redefines "this",
 *  so we can't use it inside getFuzzyFilteredChoices().
 *
 * THIS WILL PREVENT MULTIPLE instances of a fuzzy-search: Refactor to use `PromptSelectFuzzy.fetchedChoices[controlId]` instead.
 *
 * HACK: The `any` generic type arg is bc we cant be more specific and use TValue at the module scope, so it needs to support any TValue.
 */
let fetchedChoices = [];
/** Prompt for a value using a fuzzy-search to show available selections.
 */
let PromptSelectFuzzy = class PromptSelectFuzzy {
    constructor(logger, _ui, _styler) {
        this.logger = logger;
        this._ui = _ui;
        this._styler = _styler;
    }
    // private static fetchedChoices: { [controlId: string]: SelectOption<TValue>[] } = {};
    go(controlId, prompt, suggestOnly, defaultValue, searchOnRemote, fetchMethod, validationMethod) {
        var _a, _b;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            let entry; // = defaultValue;
            try {
                // TODO: Consider running this inside getFuzzyFilteredChoices()...
                // eg:
                // let fuzzySearch = (answers: PromptChoice[], input: string): Promise<PromptChoice[]> {
                //  return this.getFuzzyFilteredChoices(answers, input, fetchMethod);
                // }
                // PromptSelectFuzzy.fetchedChoices[controlId] = await fetchMethod();
                if (searchOnRemote !== true)
                    fetchedChoices = yield fetchMethod("");
                let selectedValue;
                let isValid = false;
                let invalidReason;
                while (entry === undefined || !isValid) {
                    inquirer.registerPrompt('autocomplete', autocomplete);
                    if (invalidReason)
                        this._ui.userMessage(invalidReason);
                    let selectResult = yield inquirer.prompt([{
                            type: 'autocomplete',
                            suggestOnly: suggestOnly,
                            name: controlId,
                            message: `${prompt} `,
                            source: (searchOnRemote) ? (answers, input) => fetchMethod(input) : this.getFuzzyFilteredChoices,
                            default: defaultValue
                        }]);
                    entry = selectResult[controlId];
                    selectedValue = selectResult[controlId]; // this is not entry because selectedValue should be of generic type "T"
                    this.logger.trace(`${controlId} selected`, selectedValue);
                    // Validate the selection
                    let validResult = (validationMethod) ? validationMethod(selectedValue) : true;
                    if (typeof validResult === 'boolean') {
                        isValid = validResult;
                        invalidReason = undefined;
                    }
                    else {
                        isValid = validResult.isValid;
                        invalidReason = validResult.reason;
                    }
                    if (!isValid) {
                        this.logger.trace(`${controlId} value [${selectedValue}] is invalid. ${invalidReason !== null && invalidReason !== void 0 ? invalidReason : ""}`);
                    }
                }
                return selectedValue;
            }
            catch (err) {
                this.logger.error(`Error performing a fuzzy-select for [${controlId}]: ${(_a = err.name) !== null && _a !== void 0 ? _a : ""} ${(_b = err.message) !== null && _b !== void 0 ? _b : ""}`, err.stack);
                throw err;
            }
        });
    }
    /** Performs the actual fuzzy-filtering of the already-fetched module-scoped list of available values.  */
    getFuzzyFilteredChoices(answers, input) {
        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 || "";
                // Original instructions called for this (maybe to debounce it?)
                // setTimeout(() => {
                let filtered;
                // if (parseInt(input) != NaN) {
                if (isNaN(+input)) {
                    // let options: fuzzy.FilterOptions<PromptChoice> = { extract: (ver: PromptChoice) => { return ver.value } };
                    let options = { extract: (ver) => { return ver.name; } };
                    let results = fuzzy.filter(input, fetchedChoices, options);
                    filtered = results.map((fr) => fr.original);
                }
                else {
                    // Numeric search
                    filtered = fetchedChoices.filter(p => `${p.value}`.startsWith(input));
                }
                resolve(filtered);
                // }, 20);  // is this for debouncing?
            }
            catch (err) {
                reject(err);
            }
        }));
    }
};
PromptSelectFuzzy = tslib_1.__decorate([
    (0, inversify_1.injectable)(),
    tslib_1.__param(0, (0, inversify_1.inject)(codiac_common_1.INTERFACES.IBetterLogger)),
    tslib_1.__param(1, (0, inversify_1.inject)(INTERFACES_CLI_1.INTERFACES_CLI.IUserInputProvider)),
    tslib_1.__param(2, (0, inversify_1.inject)(INTERFACES_CLI_1.INTERFACES_CLI.IOutputStyler)),
    tslib_1.__metadata("design:paramtypes", [Object, Object, Object])
], PromptSelectFuzzy);
exports.PromptSelectFuzzy = PromptSelectFuzzy;
//# sourceMappingURL=prompt-select-fuzzy.js.map