// @ts-check

/**
 * Create env file if not existing on user's machine
 *
 * @param {"" | "example" | "dev" | "staging" | "production"} name
 */
function maybeCreateEnvFile(name, callback) {
  const filename = name ? `.env.${name}` : ".env";
  const { taskIfDevAndMissingFile } = require("../utils");
  const paths = require("../paths");

  return taskIfDevAndMissingFile(
    paths.join(paths.root, filename),
    callback,
    () => {
      const gulp = require("gulp");
      const template = require("gulp-template");
      const { paramCase, snakeCase } = require("change-case");
      const { getProjectTitle } = require("../utils");
      const title = getProjectTitle();

      return gulp
        .src(paths.join(paths.self.templates, filename), { dot: true })
        .pipe(
          // @ts-ignore
          template({
            kebab: paramCase(title),
            snake: snakeCase(title),
          })
        )
        .pipe(gulp.dest(paths.root));
    }
  );
}

/**
 * Dynamically add the webpack-dev-server url. It needs to be done this way
 * because we first need some environment variables, then we need to determine
 * a free port to use, after that we can set the DEV_WDS_URL in the env file
 * so that it can be used server side too during development to load static
 * resources from webpack-dev-server memory. Then we need to reload the env
 * by recalling the task `envLoad`.
 *
 * On production just strips the DEV_WDS_URL, which should not be there in
 * general, especially in the CI, but it is probably there when building the
 * website locally.
 */
function envModify() {
  const { isProduction } = require("../config");
  const gulp = require("gulp");
  const footer = require("gulp-footer");
  const replace = require("gulp-replace");
  const paths = require("../paths");
  const { getBaseUrl } = require("../utils");

  return (
    gulp
      .src(paths.env)
      .pipe(replace(/[\n|\r]*DEV_WDS_URL.+$[.|\s|\n|\r]*(?=\S)*/gm, "\n"))
      // @ts-ignore
      .pipe(footer(isProduction ? "" : `\nDEV_WDS_URL=${getBaseUrl()}\n`))
      // @ts-ignore
      .pipe(gulp.dest(paths.root))
  );
}

/**
 * Create current .env file
 */
function envCurrent(callback) {
  return maybeCreateEnvFile("", callback);
}

/**
 * Create env "example"
 */
function envExample(callback) {
  return maybeCreateEnvFile("example", callback);
}

/**
 * Create env "dev"
 */
function envDev(callback) {
  return maybeCreateEnvFile("dev", callback);
}

/**
 * Create env "staging"
 */
function envStaging(callback) {
  return maybeCreateEnvFile("staging", callback);
}

/**
 * Create env "production"
 */
function envProduction(callback) {
  return maybeCreateEnvFile("production", callback);
}

/**
 * Require dotenv programmatically, so that we can load it after the file has
 * been generated in case it was missing and after the `envModify` dynamic
 * configuration
 */
function envLoad(callback) {
  require("dotenv").config();
  callback();
}

/**
 * Collect subtasks in a single task that respect the gulp async lifecycle by
 * calling the callback on completion.
 */
module.exports = function env(callback) {
  const gulp = require("gulp");
  return gulp.parallel(
    gulp.series(envCurrent, envLoad, envModify, envLoad),
    envExample,
    envDev,
    envStaging,
    envProduction
  )(callback);
};
