"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.findAlternativeNodeModules = findAlternativeNodeModules;
exports.findAlternativeFiles = findAlternativeFiles;

function _path() {
  const data = _interopRequireDefault(require("path"));

  _path = function () {
    return data;
  };

  return data;
}

var _schema = require("./schema");

var _path2 = require("./path");

var _config = require("./config");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

async function findAlternativeNodeModules(fs, moduleName, dir) {
  let potentialModules = [];

  let root = _path().default.parse(dir).root;

  let isOrganisationModule = moduleName.startsWith('@');

  while (dir !== root) {
    // Skip node_modules directories
    if (_path().default.basename(dir) === 'node_modules') {
      dir = _path().default.dirname(dir);
    }

    try {
      let modulesDir = _path().default.join(dir, 'node_modules');

      let stats = await fs.stat(modulesDir);

      if (stats.isDirectory()) {
        let dirContent = (await fs.readdir(modulesDir)).sort(); // Filter out the modules that interest us

        let modules = dirContent.filter(i => isOrganisationModule ? i.startsWith('@') : !i.startsWith('@')); // If it's an organisation module, loop through all the modules of that organisation

        if (isOrganisationModule) {
          await Promise.all(modules.map(async item => {
            let orgDirPath = _path().default.join(modulesDir, item);

            let orgDirContent = (await fs.readdir(orgDirPath)).sort(); // Add all org packages

            potentialModules.push(...orgDirContent.map(i => `${item}/${i}`));
          }));
        }
      }
    } catch (err) {// ignore
    } // Move up a directory


    dir = _path().default.dirname(dir);
  }

  return (0, _schema.fuzzySearch)(potentialModules.sort(), moduleName).slice(0, 2);
}

async function findAllFilesUp({
  fs,
  dir,
  root,
  basedir,
  maxlength,
  collected,
  leadingDotSlash = true,
  includeDirectories = true
}) {
  let dirContent = (await fs.readdir(dir)).sort();
  return Promise.all(dirContent.map(async item => {
    let fullPath = _path().default.join(dir, item);

    let relativeFilePath = (0, _path2.relativePath)(basedir, fullPath, leadingDotSlash);

    if (relativeFilePath.length < maxlength) {
      let stats = await fs.stat(fullPath);
      let isDir = stats.isDirectory();

      if (isDir && includeDirectories || stats.isFile()) {
        collected.push(relativeFilePath);
      } // If it's a directory, run over each item within said directory...


      if (isDir) {
        return findAllFilesUp({
          fs,
          dir: fullPath,
          root,
          basedir,
          maxlength,
          collected
        });
      }
    }
  }));
}

async function findAlternativeFiles(fs, fileSpecifier, dir, projectRoot, leadingDotSlash = true, includeDirectories = true, includeExtension = false) {
  let potentialFiles = []; // Find our root, we won't recommend files above the package root as that's bad practise

  let pkg = await (0, _config.resolveConfig)(fs, _path().default.join(dir, 'index'), ['package.json'], projectRoot);
  let pkgRoot = pkg ? _path().default.dirname(pkg) : projectRoot;
  await findAllFilesUp({
    fs,
    dir: pkgRoot,
    root: pkgRoot,
    basedir: dir,
    maxlength: fileSpecifier.length + 10,
    collected: potentialFiles,
    leadingDotSlash,
    includeDirectories
  });

  if (_path().default.extname(fileSpecifier) === '' && !includeExtension) {
    potentialFiles = potentialFiles.map(p => {
      let ext = _path().default.extname(p);

      return ext.length > 0 ? p.slice(0, -ext.length) : p;
    });
  }

  return (0, _schema.fuzzySearch)(potentialFiles, fileSpecifier).slice(0, 2);
}