import fs from 'fs-extra';
import path from 'path';
// import { prompt, Question} from 'inquirer';
import inquirer from 'inquirer';
import chalk from 'chalk';


const COMPLETED = 'SELECTION_COMPLETED';
const CANCELLED = 'SELECTION_CANCELLED';
const CHECKMARK = '\u2713';

class FilesSystemService {
  directories(directoryPath, directoryFilter ?: (joinedPath) => true) {
    return fs.readdirSync(directoryPath).filter((name) => {
      const joinedPath = path.join(directoryPath, name);
      return this.isDirectory(joinedPath) && directoryFilter(joinedPath);
    });
  }

  files(directoryPath, fileFilter = (joinedPath) => 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 {
  lastFileSelected = null;
  constructor(selectedFiles) {
    super(selectedFiles);
  }

  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(public currentPath) {
    this.currentPath = currentPath;
  }
}

class OptionsService {
  constructor(public options) {
    this.options = { ...this.defaultOptions, ...options };
  }

  get defaultOptions() {
    return {
      directoryFilter: () => true,
      fileFilter: () => true,
      root: process.cwd(),
      startingPath: process.cwd(),
      multi: true,
      pageSize: 10,
      selectedFiles: [],
      clearConsole: true,
    };
  }
}

export 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):FCResult|void => {
    (async function promptUserToSelectFiles() {
      const directories = fileSystemService.directories(
        locationService.currentPath,
        optionsService.options.directoryFilter
      );

      if (locationService.currentPath !== optionsService.options.root) {
        directories.unshift('..');
      }

      const files = 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(CHECKMARK)
              : ''
          }`;
          return { value, name };
        }),
      ];

      if (filesSelectionService.selectedFiles.length) {
        choices.push({
          name: chalk.green('-- File Selection Complete --'),
          value: COMPLETED,
        });
      }

      choices.push({
        name: chalk.red('-- Cancel  File  Selection --'),
        value: CANCELLED,
      });

      if (optionsService.options.clearConsole) {
        console.clear();
      }

      const { selection } = await 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 === COMPLETED || selection === CANCELLED) {
        return resolve({
          selectedFiles: filesSelectionService.selectedFiles,
          status: selection,
        });
      } else if (!optionsService.options.multi) {
        return resolve({
          selectedFiles: [selection],
          status: COMPLETED,
        });
      }

      if (fileSystemService.isDirectory(selection)) {
        locationService.currentPath = selection;
      } else {
        if (filesSelectionService.isSelected(selection)) {
          filesSelectionService.removeFile(selection);
        } else {
          filesSelectionService.selectFile(selection);
        }
      }

      promptUserToSelectFiles();
    })();
  });
};
export type FCResult = {
  selectedFiles:Array<string>
  status:'SELECTION_COMPLETED'|'SELECTION_CANCELLED'
}
// const exports = {
//   COMPLETED,
//   CANCELLED,
//   selectFiles,
// };