"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectFiles = exports.EnumRetrievalMode = exports.CHECKMARK = exports.CANCELLED = exports.COMPLETED = void 0;
const tslib_1 = require("tslib");
const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');
const chalk = require('chalk');
exports.COMPLETED = 'SELECTION_COMPLETED';
exports.CANCELLED = 'SELECTION_CANCELLED';
exports.CHECKMARK = '\u2713';
/** Indicator of whether the user experience is to return files or directories. */
var EnumRetrievalMode;
(function (EnumRetrievalMode) {
    EnumRetrievalMode["file"] = "file";
    EnumRetrievalMode["directory"] = "directory";
})(EnumRetrievalMode = exports.EnumRetrievalMode || (exports.EnumRetrievalMode = {}));
class FilesSystemService {
    directories(directoryPath, directoryFilter = (dn) => true) {
        return fs.readdirSync(directoryPath).filter((name) => {
            const joinedPath = path.join(directoryPath, name);
            return this.isDirectory(joinedPath) && directoryFilter(joinedPath);
        });
    }
    files(directoryPath, fileFilter = (fileName) => true) {
        return fs.readdirSync(directoryPath).filter((name) => {
            const joinedPath = path.join(directoryPath, name);
            return this.isFile(joinedPath) && fileFilter(joinedPath);
        });
    }
    isDirectory(directoryPath) {
        return fs.statSync(directoryPath).isDirectory();
    }
    isFile(filePath) {
        return fs.statSync(filePath).isFile();
    }
}
class FilesSelectionService extends Set {
    constructor(selectedFiles) {
        super(selectedFiles);
        this.lastFileSelected = null;
    }
    get selectedFiles() {
        return Array.from(this);
    }
    isSelected(file) {
        return this.has(file);
    }
    selectFile(file) {
        this.add(file);
        this.lastFileSelected = file;
    }
    removeFile(file) {
        this.delete(file);
    }
}
class LocationService {
    constructor(currentPath) {
        this.currentPath = currentPath;
    }
}
class OptionsService {
    constructor(options) {
        this.options = options;
        this.options = Object.assign(Object.assign({}, this.defaultOptions), options);
    }
    get defaultOptions() {
        return {
            directoryFilter: () => true,
            fileFilter: () => true,
            root: process.cwd(),
            startingPath: process.cwd(),
            multi: false,
            pageSize: 10,
            selectedFiles: [],
            clearConsole: true,
            mode: EnumRetrievalMode.file
        };
    }
}
const selectFiles = function (options = {}) {
    const optionsService = new OptionsService(options);
    const locationService = new LocationService(optionsService.options.startingPath);
    const fileSystemService = new FilesSystemService();
    const filesSelectionService = new FilesSelectionService(optionsService.options.selectedFiles);
    return new Promise((resolve) => {
        (function promptUserToSelectFiles() {
            return tslib_1.__awaiter(this, void 0, void 0, function* () {
                const directories = fileSystemService.directories(locationService.currentPath, optionsService.options.directoryFilter);
                if (locationService.currentPath !== optionsService.options.root) {
                    directories.unshift('..');
                }
                // Dont show any files if theyre looking for directories.
                const files = (optionsService.options.mode == EnumRetrievalMode.directory) ? [] : fileSystemService.files(locationService.currentPath, optionsService.options.fileFilter);
                const choices = [
                    ...directories.map((directoryName) => {
                        const value = path.join(locationService.currentPath, directoryName);
                        const name = chalk.yellow(directoryName);
                        return { value, name };
                    }),
                    ...files.map((fileName) => {
                        const value = path.join(locationService.currentPath, fileName);
                        const name = `${fileName} ${filesSelectionService.isSelected(value)
                            ? chalk.green(exports.CHECKMARK)
                            : ''}`;
                        return { value, name };
                    }),
                ];
                switch (optionsService.options.mode) {
                    case EnumRetrievalMode.directory:
                        // if (filesSelectionService.selectedFiles.length) {
                        choices.unshift({
                            name: chalk.green('.  (Select this folder)'),
                            value: exports.COMPLETED,
                        });
                        // }
                        choices.push({
                            name: chalk.red('-- Cancel  Folder  Selection --'),
                            value: exports.CANCELLED,
                        });
                        break;
                    case EnumRetrievalMode.file:
                        if (filesSelectionService.selectedFiles.length) {
                            choices.push({
                                name: chalk.green('-- File Selection Complete --'),
                                value: exports.COMPLETED,
                            });
                        }
                        choices.push({
                            name: chalk.red('-- Cancel  File  Selection --'),
                            value: exports.CANCELLED,
                        });
                        break;
                }
                if (optionsService.options.clearConsole) {
                    console.clear();
                }
                const { selection } = yield inquirer.prompt([
                    {
                        type: 'list',
                        message: `Select file(s) in ${locationService.currentPath}`,
                        name: 'selection',
                        pageSize: optionsService.options.pageSize,
                        choices,
                        default: () => filesSelectionService.lastFileSelected,
                    },
                ]);
                if (optionsService.options.clearConsole) {
                    console.clear();
                }
                if (selection === exports.COMPLETED || selection === exports.CANCELLED) {
                    let result = {
                        selectedFiles: filesSelectionService.selectedFiles,
                        status: selection,
                    };
                    if (optionsService.options.mode == EnumRetrievalMode.directory) {
                        result.selectedFiles = [locationService.currentPath];
                    }
                    return resolve(result);
                }
                else if (optionsService.options.mode == EnumRetrievalMode.file
                    && fileSystemService.isFile(selection)
                    && !optionsService.options.multi // Complete if we're in file mode and looking for just one.
                ) {
                    return resolve({
                        selectedFiles: [selection],
                        status: exports.COMPLETED,
                    });
                }
                if (fileSystemService.isDirectory(selection)) {
                    locationService.currentPath = selection;
                }
                else {
                    if (filesSelectionService.isSelected(selection)) {
                        filesSelectionService.removeFile(selection);
                    }
                    else {
                        filesSelectionService.selectFile(selection);
                    }
                }
                promptUserToSelectFiles();
            });
        })();
    });
};
exports.selectFiles = selectFiles;
//# sourceMappingURL=file-selector.js.map