// @ts-check

/**
 * Get core library sync elements folders
 *
 * @returns {string[]}
 */
function getCoresyncFolders() {
  const { config: projectConfig } = require("../config").pkg;
  const { getCoreLibraryPkg } = require("../utils/coreLibrary");
  const { config: libConfig } = getCoreLibraryPkg();
  const libSync =
    libConfig && libConfig["core-sync"] ? libConfig["core-sync"] : [];
  const projectSync =
    projectConfig && projectConfig["core-sync"]
      ? projectConfig["core-sync"]
      : [];

  let allFolders = libSync.concat(projectSync);
  allFolders = allFolders.filter((item, index) => {
    return allFolders.indexOf(item) == index;
  });
  return allFolders;
}

/**
 * Generate route
 */
module.exports = function coreSync(callback) {
  const {
    coreLibraryExists,
    getCoreLibraryPath,
    getCoreLibraryPkg,
  } = require("../utils/coreLibrary");

  if (!coreLibraryExists()) {
    throw Error("There is no core library installed!");
  }

  const log = require("fancy-log");
  const chalk = require("chalk");
  const paths = require("../paths");
  const { isProduction } = require("../config");
  const opt = require("../utils/cli").getCliOption();
  const optNames = opt ? opt.split(",") : "all";
  const coreLibRoot = getCoreLibraryPath();
  const corePkg = getCoreLibraryPkg();
  const pkgInfo = (name) =>
    `"${corePkg.name}${name ? "/" + name : ""}" v${corePkg.version}`;

  const optNamesMap =
    optNames === "all"
      ? {}
      : optNames.reduce((obj, name) => {
          obj[name] = true;
          return obj;
        }, {});

  const folders = getCoresyncFolders();
  const srcPaths = [];
  const srcNames = [];

  for (let i = 0; i < folders.length; i++) {
    const name = folders[i];
    if (optNames === "all" || optNamesMap[name]) {
      srcPaths.push({
        dirPath: coreLibRoot + "-" + name,
        name,
      });
      if (srcNames.indexOf(name) === -1) {
        srcNames.push(name);
      }
    }
  }

  log(
    chalk.greenBright(
      srcNames.length > 1
        ? `Syncing core elements from ${pkgInfo()}: `
        : `Syncing core element from ${pkgInfo()}: `
    ) + chalk.green(srcNames.join(", "))
  );

  if (!isProduction) {
    log();
  }

  const gulp = require("gulp");
  const flatmap = require("gulp-flatmap");
  const footer = require("gulp-footer");
  const gulpIf = require("gulp-if");
  const rename = require("gulp-rename");
  const { paramCase, pascalCase } = require("change-case");
  // console.log("srcPaths", srcPaths);

  return gulp
    .src(
      srcPaths.map(({ dirPath }) => dirPath),
      { allowEmpty: true }
    )
    .pipe(
      flatmap(function (stream, dir) {
        const coreElData = srcPaths.filter(
          ({ dirPath }) => dirPath === dir.path
        )[0];
        if (!coreElData) return stream;
        const { name, dirPath } = coreElData;
        return gulp
          .src([
            paths.join(dirPath, "*.php"),
            paths.join(dirPath, "/!(node_modules|examples)/**/*.php"),
          ])
          .pipe(
            rename((path) => {
              const isBlade = path.basename.endsWith(".blade");
              // path dirname is e.g. "forms" or "."
              if (path.dirname === ".") {
                path.basename = isBlade ? name : pascalCase(name);
              } else {
                path.basename = isBlade ? `${name}-` : pascalCase(name);
                path.basename += isBlade
                  ? paramCase(path.dirname)
                  : pascalCase(path.dirname);
              }
              if (isBlade) {
                path.basename += ".blade";
              }

              path.dirname = "";
            })
          )
          .pipe(
            gulpIf(
              "*.blade.php",
              footer(`\n{{-- Synced with "${pkgInfo(name)} --}}`)
            )
          )
          .pipe(gulp.dest(paths.frontend.dest.core));
      })
    );
};
