#!/usr/bin/env node

import commander from "commander";
import loglevel from "loglevel";

import { changelogs } from "./changelogs";
import { clean } from "./clean";
import { configs } from "./configs";
import { CLEAN, DEBUG, SILENT } from "./constants";
import { indexer } from "./indexer";
import { libsize } from "./libsize";
import { release, RELEASE_TYPES, toReleaseType } from "./release";
import { sandbox } from "./sandbox";
import { sassdoc } from "./sassdoc";
import { shared } from "./shared";
import { themes } from "./themes";
import { umd } from "./umd";
import { copyStyles } from "./utils";
import { variables } from "./variables";
import { watch } from "./watch";

const argv = process.argv.slice(2);

if (argv.includes(DEBUG)) {
  loglevel.setLevel("debug");
} else if (argv.includes(SILENT)) {
  loglevel.setLevel("error");
} else {
  loglevel.setLevel("info");
}

const createCommand = (
  command: string,
  cleanable: boolean = false
): commander.Command => {
  const instance = commander
    .command(command)
    .option(DEBUG, "Enables the verbose logging to help debug errors.")
    .option(SILENT, "Disables all logging.");

  if (cleanable) {
    return instance.option(
      CLEAN,
      "Removes the existing files before executing."
    );
  }

  return instance;
};

createCommand("clean")
  .description("Cleans all the distributables for all publishable packages.")
  .action(() => clean());

createCommand("styles")
  .description(
    "Copies all the SCSS files into the dist folder as well as creating non-webpack specific versions."
  )
  .action(() => copyStyles());

createCommand("sassdoc")
  .description(
    "Creates the sassdoc for the documentation site in all scoped packages."
  )
  .action(() => sassdoc());

createCommand("variables")
  .description("Creates the `src/scssVariables` file in all scoped packages.")
  .action(() => variables());

createCommand("changelogs")
  .description("Updates the changelogs to be a bit prettier.")
  .action(() => changelogs());

createCommand("configs")
  .description(
    "Re-generates all the `tsconfig.*` files for the Typescript project references."
  )
  .action(() => configs());

createCommand("copy-shared", true)
  .description(
    "Copies all the shared markdown files and utils throughout the repo into the documentation folder."
  )
  .action(({ clean = false }) => shared(clean));

createCommand("doc-index")
  .description(
    "Indexes (terribly) metadata throughout react-md for the documentation site."
  )
  .action(() => indexer());

createCommand("release")
  .option(
    "-t, --type <type>",
    `The release type. This should be one of: [ ${RELEASE_TYPES.join(", ")} ]`,
    toReleaseType
  )
  .option(
    "-b, --blog",
    "Updates the command to wait for the blog to be written before triggering the release. " +
      "This will default to `true` when the release type is not one of the `pre*` types."
  )
  .option(
    "--yes",
    "Passes `--yes` to the `lerna version` and `lerna publish` commands"
  )
  .description("Goes through the steps of releasing a new version of react-md.")
  .action(({ yes = false, blog = undefined, type = "" }) =>
    release(type, blog, yes)
  );

createCommand("sandbox", true)
  .option(
    "-p, --pattern [pattern]",
    "An optional glob pattern to use. This should be quoted if using asterisks"
  )
  .option("-d, --demo [demo]", "An optional demo pattern regex string filter.")
  .description("Creates the `*-Sandbox.json` files in the documentation site.")
  .action(({ pattern = "*", demo = "", clean = false }) =>
    sandbox(pattern, demo, clean)
  );

createCommand("libsize")
  .option(
    "--no-umd",
    "Boolean if the UMD bundles should be ignored in the output."
  )
  .option(
    "--force-umd",
    "Force recompiles the umd bundles since the bundles are only built if none can be found."
  )
  .option(
    "--no-themes",
    "Boolean if the CSS bundles should be ignored in the output."
  )
  .option(
    "--force-themes",
    "Force recompiles the pre-compiled themes since these themes are only created if none can be found."
  )
  .option(
    "--stage-changes",
    "Boolean if any changes to the documentation pages due to libsize changes should be added to the git index."
  )
  .description(
    "Prints the gzpped size for the entire library based on the UMD bundles and the pre-compiled themes."
  )
  .action(
    ({
      umd = true,
      forceUmd = false,
      themes = true,
      forceThemes = false,
      stageChanges = false,
    }) => libsize({ umd, forceUmd, themes, forceThemes, stageChanges })
  );

createCommand("themes")
  .description(
    "Creates all the pre-compiled css themes in the root `/themes` folder. " +
      "This really shouldn't be run other than during the release script since`" +
      "the `/themes` folder is ignored by git until a release is tagged."
  )
  .action(() => themes());

createCommand("umd")
  .description(
    "Compiles the UMD bundles for `react-md`. This really shouldn't be used as it's handled by the `release` script automatically."
  )
  .action(() => umd());

createCommand("watch")
  .option(
    "--cjs",
    "Spin up a commonjs tsc watcher as well instead of only the ejs watcher."
  )
  .description(
    "A custom watch script that handles copying all changed scss files as well as starting tsc watchers."
  )
  .action(({ cjs = false }) => watch(cjs));

commander.parse(process.argv);
