var fs = require('fs');
var path = require('path');
var gulp = require('gulp');
var webpack = require('webpack');
var uglify = require('uglify-js');
var log = require('fancy-log');
var format = require('date-format');
var del = require('del');

var bundleFileName = 'workerpool.js'
var minifiedFileName = 'workerpool.min.js'

// generate banner with today's date and correct version
function createBanner() {
  var today = format.asString('yyyy-MM-dd', new Date()); // today, formatted as yyyy-MM-dd
  var version = require('./package.json').version;  // module version

  return String(fs.readFileSync('./src/header.js'))
      .replace('@@date', today)
      .replace('@@version', version);
}

var bannerPlugin = new webpack.BannerPlugin({
  banner: createBanner(),
  entryOnly: true,
  raw: true
});

var webpackConfig = {
  entry: './src/index.js',
  target: ['web', 'es5'],
  mode: 'production',
  output: {
    library: 'workerpool',
    libraryTarget: 'umd',
    path: path.join(__dirname, 'dist'),
    filename: bundleFileName,
    umdNamedDefine: true,
    globalObject: '(typeof self !== \'undefined\' ? self : this)'
  },
  plugins: [
    bannerPlugin
  ],
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  },
  node: false, // do not include node poly fills for process, __dirname, etc
  optimization: {
    // We no not want to minimize our code.
    minimize: false
  },
  devtool: 'source-map'
};

var webpackMinifyConfig = {
  ...webpackConfig,
  optimization: {
    minimize: true
  },
  output: {
    ...webpackConfig.output,
    filename: minifiedFileName
  }
}

var webpackWorkerConfig = {
  ...webpackConfig,
  entry: './src/worker.js',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'worker.js'
  }
};

// create a single instance of the compiler to allow caching
var compiler = webpack(webpackConfig);
var compilerMinify = webpack(webpackMinifyConfig);

gulp.task('clean', function () {
  return del([
    'dist/**/*'
  ])
});

gulp.task('bundle-worker', function (done) {
  webpack(webpackWorkerConfig).run(function (err, stats) {
    if (err) {
      log(err);
    }

    var info = stats.toJson();

    if (stats.hasWarnings()) {
      log('Webpack warnings:\n' + info.warnings.join('\n'));
    }

    if (stats.hasErrors()) {
      log('Webpack errors:\n' + info.errors.join('\n'));
      done(new Error('Compile failed'));
    }

    log('bundled worker ./dist/worker.js');

    var result = uglify.minify(String(fs.readFileSync('./dist/worker.js')));

    if (result.error) {
      throw result.error;
    }

    // create embeddedWorker.js
    var embedded = '/**\n' +
        ' * embeddedWorker.js contains an embedded version of worker.js.\n' +
        ' * This file is automatically generated,\n' +
        ' * changes made in this file will be overwritten.\n' +
        ' */\n' +
        'module.exports = ' + JSON.stringify(result.code) + ';\n';

    fs.writeFileSync('./src/generated/embeddedWorker.js', embedded);

    log('generated embedded worker ./src/generated/embeddedWorker.js');
    done();
  });
});

gulp.task('bundle-workerpool', function (done) {
  // update the banner contents (has a date in it which should stay up to date)
  bannerPlugin.banner = createBanner();

  // note in browserify we would do something like:
  // browserify ./index.js -o dist/workerpool.js -s workerpool --no-builtins --insert-global-vars none

  compiler.run(function (err, stats) {
    if (err) {
      log(err);
    }

    var info = stats.toJson();

    if (stats.hasWarnings()) {
      log('Webpack warnings:\n' + info.warnings.join('\n'));
    }

    if (stats.hasErrors()) {
      log('Webpack errors:\n' + info.errors.join('\n'));
      done(new Error('Compile failed'));
    }

    log(`bundled ./dist/${bundleFileName}`);

    done();
  });
});

gulp.task('minify-workerpool', function (done) {
  // update the banner contents (has a date in it which should stay up to date)
  bannerPlugin.banner = createBanner();

  compilerMinify.run(function (err, stats) {
    if (err) {
      log(err);
    }

    var info = stats.toJson();

    if (stats.hasWarnings()) {
      log('Webpack warnings:\n' + info.warnings.join('\n'));
    }

    if (stats.hasErrors()) {
      log('Webpack errors:\n' + info.errors.join('\n'));
      done(new Error('Compile failed'));
    }

    log(`bundled ./dist/${bundleFileName}`);

    done();
  });
});

var tasks = gulp.series('clean', 'bundle-worker', 'bundle-workerpool', 'minify-workerpool');

// The default task (called when you run `gulp`)
gulp.task('default', tasks);

// The watch task (to automatically rebuild when the source code changes)
gulp.task('watch', gulp.series(tasks, function () {
  gulp.watch(['index.js', 'src/**/*.js', '!src/generated/**'], tasks);
}));
