"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuiltInCliUserInput = void 0;
const tslib_1 = require("tslib");
const path = require("path");
const core_1 = require("@oclif/core");
const inquirer = require("inquirer");
const file_selector_1 = require("./file-selector");
const inversify_1 = require("inversify");
// // Moved to ops-common
// export class FolderSelectionOptions {
//   /** The path under which the user is allowed to navigate (optional: Defaults to the current path).
//    * This path is also acts as the parent folder from which any relative path gets derived. */
//   public root?: string
//   /** The folder to begin the search within (optional: defaults to the current path) */
//   public startingPath?: string;
//   /** Causes the selection to be returned as a path relative to "root" (optional: defaults to false).  */
//   public asRelative?: boolean;
// }
// // Moved to ops-common
// export class FileSelectionOptions extends FolderSelectionOptions {
//   /** List of file extensions (without the period '.') on which to filter the available files. */
//   public extensions?: string[];
// }
// /** Just documenting the options arg from cli-select-file, cuz they dont have a type def. */
// type CliSelectFileOptions = {
//   /** integer, Default value is 10 */
//   pageSize?: number,
//   /** Defaults to true to allow for selection of multiple files */
//   multi?: boolean,
//   /** Files that will initially be selected */
//   selectedFiles?: string[],
//   /** Defaults to true */
//   clearConsole?: boolean,
//   /** Where the user will initially be prompted to select files
//   Defaults to process.cwd() */
//   startingPath?: string,
//   /** The top level directory the user has access to
//   Defaults to process.cwd() */
//   root?: string,
//   /** Return false for any directory that you do not want to appear in the cli 
//   ```
//   directoryFilter?: (directoryName) => {
//       return !/node_modules$/gi.test(directoryName);
//   },
//   ```
//   */
//   directoryFilter?: (directoryName: string) => boolean,
//   /** Return false for any file that you do not want to appear in the cli 
//     ```
//     fileFilter: (fileName) => {
//       return !/index.js$/gi.test(fileName);
//     },
//     ```
//   */
//   fileFilter?: (fileName: string) => boolean
// } 
// type CLISelectFileResult = {
//   selectedFiles: string[],
//   status: string
// }
/** Uses cli-ux and inquirer libraries to retrieve values from the user.
 * Requires a TTY console.
 * @see https://www.npmjs.com/package/inquirer
 */
let BuiltInCliUserInput = class BuiltInCliUserInput {
    constructor() {
    }
    // ----------------------------------------------------
    // ALSO:   Consider using this lib...
    //         "prompts"
    //         https://www.npmjs.com/package/prompts
    //         (good docs, adoption, interface, and smooth ux)
    //         * text
    //         * password
    //         * invisible
    //         * number
    //         * confirm
    //         * list
    //         * toggle
    //         * select
    //         * multiselect
    //         * autocompleteMultiselect
    //         * autocomplete
    //         * date
    // ----------------------------------------------------
    // ----------------------------------------------------
    // For spinners...
    //        "ora"           https://www.npmjs.com/package/ora
    //        "cli-spinners"  https://www.npmjs.com/package/cli-spinners (components for ora)
    //        "nanospinner"   https://www.npmjs.com/package/nanospinner
    //        "tinyspinner"   https://www.npmjs.com/package/tiny-spinner
    // ----------------------------------------------------
    // ----------------------------------------------------
    // For tables...
    //        "list-it"       https://www.npmjs.com/package/list-it
    //        "easy-table"    https://www.npmjs.com/package/easy-table
    // ----------------------------------------------------
    userMessage(message) {
        core_1.ux.log(message);
    }
    prompt(id, prompt, required = false, defaultValue, validator) {
        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 {
                    let output;
                    // "Required" is not supported here.
                    if (validator === undefined) {
                        let result = yield inquirer.prompt({ type: "input", name: id, message: prompt, default: defaultValue });
                        output = (result[id]); // <--- mind this!
                    }
                    else {
                        let validation;
                        let candidate;
                        while (candidate === undefined || (validation === null || validation === void 0 ? void 0 : validation.isValid) !== true) {
                            let promptRes = yield inquirer.prompt({ type: "input", name: id, message: prompt, default: defaultValue });
                            candidate = (promptRes[id]); // <--- mind this!
                            validation = validator.isValid(candidate);
                            if (!validation.isValid) {
                                this.userMessage(`INVALID: ${(_a = validation.reason) !== null && _a !== void 0 ? _a : ""}`);
                            }
                        }
                        output = candidate;
                    }
                    resolve(output);
                }
                catch (err) {
                    reject(err);
                }
            }));
            // // Prompts using cli-ux
            // let options = <IPromptOptions>{ prompt: prompt };
            //     if (required) options.required = required;
            //     if (defaultValue) options.default = <any>defaultValue;  // this doesnt work
            // return cli.prompt("myField", options);
        });
    }
    promptPassword(id, prompt, defaultValue, validator) {
        var _a;
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            // Prompts using cli-ux
            let options = { prompt: prompt, type: "hide", required: true };
            if (validator === undefined) {
                return core_1.ux.prompt(id, options);
            }
            else {
                let validation;
                let candidate;
                while (candidate === undefined || (validation === null || validation === void 0 ? void 0 : validation.isValid) !== true) {
                    candidate = yield core_1.ux.prompt(id, options);
                    validation = validator.isValid(candidate);
                    if (!validation.isValid) {
                        this.userMessage(`INVALID: ${(_a = validation.reason) !== null && _a !== void 0 ? _a : ""}`);
                    }
                }
                return candidate;
            }
        });
    }
    promptConfirm(id, prompt, defaultValue = true) {
        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 defaultChoice = (defaultValue == undefined) ? false : defaultValue;
                    let result = yield inquirer.prompt({ type: 'confirm', name: id, message: prompt, default: defaultChoice });
                    let output = (result[id]);
                    resolve(output);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    // TODO:  Add param for FuzzyAutoSelect 
    promptSelect(id, prompt, choices, multiSelect, loop, validator) {
        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 inqChoices = choices.map(c => {
                        var _a;
                        return {
                            name: (typeof c == "string") ? c : c.name,
                            value: (typeof c == "string") ? c : ((_a = c.value) !== null && _a !== void 0 ? _a : c.name)
                        };
                    });
                    let promptModule = { type: 'list', name: 'mySelectField', message: prompt, choices: inqChoices };
                    if (validator)
                        promptModule.validate = validator; // <-- this isnt firing - are we doing this wrong?
                    if (loop !== undefined)
                        promptModule.loop = loop;
                    let result = yield inquirer.prompt(promptModule);
                    let selected = result.mySelectField;
                    resolve(selected);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    promptSelectFile(id, prompt, fileOptions) {
        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 {
                    // see https://www.npmjs.com/package/select-files-cli
                    let selectorOptions = {
                        clearConsole: false,
                        multi: false
                    };
                    if (fileOptions.root)
                        selectorOptions.root = fileOptions.root;
                    if (fileOptions.startingPath) {
                        if (fileOptions.root && !fileOptions.startingPath.startsWith(fileOptions.root)) {
                            throw new Error(`Starting path for file selection [${fileOptions.startingPath}] was not inside the folder specified as "root" [${fileOptions.root}].`);
                        }
                        selectorOptions.startingPath = fileOptions.startingPath;
                    }
                    if (fileOptions.extensions && fileOptions.extensions.length > 0) {
                        let ptn = `\\.(${fileOptions.extensions.join("|")})$`;
                        let rx = new RegExp(ptn, "i");
                        selectorOptions.fileFilter = (fileName) => rx.test(fileName);
                    }
                    // WAIT FOR USER TO NAVIAGATE AND MAKE A SELECTION...
                    let result = yield (0, file_selector_1.selectFiles)(selectorOptions);
                    // console.dir(result);
                    let selected;
                    if (result.status == file_selector_1.COMPLETED && result.selectedFiles && result.selectedFiles.length > 0) {
                        selected = result.selectedFiles[0];
                        if (fileOptions.asRelative) {
                            let root = (_a = fileOptions.root) !== null && _a !== void 0 ? _a : process.cwd();
                            selected = path.relative(root, selected);
                        }
                    }
                    else {
                        throw new Error(`Cancelled file selection.`);
                    }
                    resolve(selected);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    promptSelectFolder(id, prompt, folderOptions) {
        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 {
                    // see https://www.npmjs.com/package/select-files-cli
                    let selectorOptions = {
                        clearConsole: false,
                        multi: false,
                        mode: file_selector_1.EnumRetrievalMode.directory
                    };
                    if (folderOptions.root)
                        selectorOptions.root = folderOptions.root;
                    if (folderOptions.startingPath) {
                        if (folderOptions.root && !folderOptions.startingPath.startsWith(folderOptions.root)) {
                            throw new Error(`Starting path for file selection [${folderOptions.startingPath}] was not inside the folder specified as "root" [${folderOptions.root}].`);
                        }
                        selectorOptions.startingPath = folderOptions.startingPath;
                    }
                    // WAIT FOR USER TO NAVIAGATE AND MAKE A SELECTION...
                    let result = yield (0, file_selector_1.selectFiles)(selectorOptions);
                    // console.dir(result);
                    let selected;
                    if (result.status == file_selector_1.COMPLETED && result.selectedFiles && result.selectedFiles.length > 0) {
                        selected = result.selectedFiles[0];
                        if (folderOptions.asRelative) {
                            let root = (_a = folderOptions.root) !== null && _a !== void 0 ? _a : process.cwd();
                            selected = path.relative(root, selected);
                        }
                    }
                    else {
                        throw new Error(`Cancelled folder selection.`);
                    }
                    resolve(selected);
                }
                catch (err) {
                    reject(err);
                }
            }));
        });
    }
    openUrl(url) {
        return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            try {
                console.log(`Cannot open url[${url}]: OpenUrl is not yet implemented for BuiltInCliUserInput`);
                resolve();
            }
            catch (err) {
                reject(err);
            }
        }));
    }
    startSpinner(userMessage) {
        core_1.ux.action.start(userMessage); // (this._styler.hilite(userMessage));
    }
    stopSpinner(userMessage) {
        core_1.ux.action.stop(userMessage);
    }
};
BuiltInCliUserInput = tslib_1.__decorate([
    (0, inversify_1.injectable)(),
    tslib_1.__metadata("design:paramtypes", [])
], BuiltInCliUserInput);
exports.BuiltInCliUserInput = BuiltInCliUserInput;
//# sourceMappingURL=built-in-cli-user-input.js.map