const joi = require("joi");
const fs = require("fs-extra");
const path = require("path");

function parseArgs({
  suluDir: _suluDir,
  writeDir: _writeDir,
  pluginPaths: __pluginPaths,
  version = "",
  _w = false,
  _v = false,
  _s = false,
  _p = false,
  _t = false,
}) {
  const _pluginPaths = __pluginPaths.split(",").filter((x) => x);

  const {
    error,
    value: {
      suluDir,
      writeDir,
      pluginPaths,
      stopIfWriteDirNotEmpty,
      dontStopIfPluginPathsEmpty,
      suppressLogging,
      incrementalBuild,
      reloadOnChanges,
    },
  } = joi
    .object({
      suluDir: joi.string().required(),
      writeDir: joi.string().required(),
      pluginPaths: joi.array().items(joi.string().allow("")),
      stopIfWriteDirNotEmpty: joi.boolean().optional().default(false),
      dontStopIfPluginPathsEmpty: joi.boolean().optional().default(false),
      suppressLogging: joi.boolean().optional().default(false),
      incrementalBuild: joi.boolean().optional().default(false),
      reloadOnChanges: joi.boolean().optional().default(false),
    })
    .validate({
      suluDir: _suluDir,
      writeDir: _writeDir,
      pluginPaths: _pluginPaths,
      stopIfWriteDirNotEmpty: _w,
      dontStopIfPluginPathsEmpty: _v,
      suppressLogging: _s,
      incrementalBuild: _p,
      reloadOnChanges: _t,
    });

  if (error) {
    throw new Error(error);
  }

  if (reloadOnChanges && (!incrementalBuild)) {
    throw new Error("-t flag must be used with both -o and -p flags");
  }

  const log = (...s) => {
    if (!suppressLogging) {
      console.log(...s);
    }
  };

  // check that sulu directory exists, is readable, and is not empty.
  if (!fs.existsSync(suluDir)) {
    throw new Error(
      `Sulu directory passed "${suluDir}" is not visible to the script.`
    );
  }
  if (!fs.readdirSync(suluDir).length) {
    throw new Error(`Sulu directory passed "${suluDir}" empty`);
  }
  if (!dontStopIfPluginPathsEmpty && !pluginPaths.length) {
    throw new Error("Plugin paths empty while v flag not set");
  }

  const manifests = pluginPaths.map((p) => {
    if (!fs.existsSync(p)) {
      throw new Error(`Passed plugin path "${p}" does not exist`);
    }

    if (!fs.existsSync(path.join(p, "suluPluginManifest.json"))) {
      throw new Error(
        `Plugin under "${path.join(
          p,
          "suluPluginManifest.json"
        )}" does not contain the required suluPluginManifest.json file.`
      );
    }

    const { error: jerror, value } = joi
      .object({
        pattern: joi.string().required(),
        excludePattern: joi.string().allow("").optional().default("(?!)"),
        integrate_package_file_dependencies: joi.boolean(),
        integrate_package_file_dev_dependencies: joi.boolean(),
        // transferRootFolders: joi.string().optional().default("src")
      })
      .validate(fs.readJSONSync(path.join(p, "suluPluginManifest.json")));

    if (jerror) {
      throw new Error(
        `Failed to validate ${path.join(
          p,
          "suluPluginManifest.json"
        )}: ${jerror}`
      );
    }

    return {
      absolutePath: path.resolve(p),
      manifest: value,
    };
  });

  if (fs.existsSync(writeDir)) {
    if (stopIfWriteDirNotEmpty) {
      throw new Error(
        `"${writeDir}" exists and is not empty but flag w - which checks that build directories are empty - was set.`
      );
    }
    if (incrementalBuild) {
      log("Write directory exists, build incremental so leaving as is.");
      // fs.readdirSync(writeDir)
      //   .filter(src => !["node_modules", "yarn.lock"].find(x => src.includes(x)))
      //   .forEach(src => fs.removeSync(path.join(writeDir, src)));
    } else {
      log("Write directory exists, deleting all contents...");
      fs.emptyDirSync(writeDir);
    }
  } else {
    log("Write directory does not exist, creating empty...");
    fs.emptyDirSync(writeDir);
  }

  // resolve to end up with absolute paths only
  return {
    version,
    suluDir: path.resolve(suluDir),
    buildOutputPath: path.resolve(writeDir),
    manifests,
    log,
    options: {
      reloadOnChanges,
      incrementalBuild,
    },
  };
}

module.exports = {
  parseArgs,
};
