// gulpfile.js
// Copyright (C) 2021 Digital Telepresence, LLC
// License: Apache-2.0

'use strict';

const path = require('path');

const gulp = require('gulp');
const nodemon = require('gulp-nodemon');
const plumber = require('gulp-plumber');
const less = require('gulp-less');
const jshint = require('gulp-jshint');

const webpack = require('webpack-stream');
const { GenerateSW } = require('workbox-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const browserSync = require('browser-sync').create();

function util_start_browsersync ( ) {
  return new Promise((resolve, reject) => {
    browserSync.init({
      proxy: {
        target: 'http://dev.sites.digitaltelepresence.com:3020',
        ws: true,
        reqHeaders: {
          'X-Forwarded-For': '127.0.0.1',
          'X-Forwarded-Proto': 'https',
        },
        cookies: { stripDomain: false },
      },
      host: 'dev.sites.digitaltelepresence.com',
      open: 'external',
      https: {
        key: path.join(__dirname, 'ssl', 'dtp-sites.key'),
        cert: path.join(__dirname, 'ssl', 'dtp-sites.crt'),
      },
      port: 3320,
      cors: true,
      ui: {
        port: 3620,
      },
      notify: false,
      ghostMode: {
        clicks: false,
        forms: false,
        scroll: true,
      },
      logLevel: 'info',
      callbacks: {
        ready: function (err, bs) {
          if (err) {
            console.log('BrowserSync start error', err);
            return reject(err);
          }
          console.log('BrowserSync ready');
          return resolve(bs);
        },
      },
    });
  });
}

async function dtp_less_dark ( ) {
  return gulp
    .src('./client/less/dtp-dark.less')
    .pipe(plumber())
    .pipe(less({ paths: [ __dirname ], math: 'always' }))
    .pipe(gulp.dest('./dist/css'))
    .pipe(browserSync.stream());
}

async function dtp_less_light ( ) {
  return gulp
    .src('./client/less/dtp-light.less')
    .pipe(plumber())
    .pipe(less({ paths: [ __dirname ], math: 'always' }))
    .pipe(gulp.dest('./dist/css'))
    .pipe(browserSync.stream());
}

function dtp_jshint_client ( ) {
  var jsrc = 'client/js/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  .pipe(jshint.reporter('fail'))
  .pipe(browserSync.stream())
  ;
}

function dtp_jshint_lib ( ) {
  var jsrc = 'lib/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  .pipe(jshint.reporter('fail'))
  .pipe(browserSync.stream())
  ;
}

function dtp_jshint_workers ( ) {
  var jsrc = 'app/workers/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  ;
}

function dtp_jshint_services ( ) {
  var jsrc = 'app/services/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  ;
}

function dtp_jshint_models ( ) {
  var jsrc = 'app/models/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  .pipe(jshint.reporter('fail'))
  .pipe(browserSync.stream())
  ;
}

function dtp_jshint_controllers ( ) {
  var jsrc = 'app/controllers/**/*.js';
  return gulp
  .src(jsrc)
  .pipe(jshint())
  .pipe(jshint.reporter('dtp-jshint-reporter'))
  .pipe(jshint.reporter('fail'))
  .pipe(browserSync.stream())
  ;
}

/*
 * Shared Webpack settings detween dev & prod
 */
const webpackDevtool = 'source-map';
const webpackResolve = {
  alias: {
    dtp: path.resolve(__dirname, 'lib', 'client', 'js'),
  },
  extensions: ['.js'],
};
const webpackOutput = {
  filename: 'dtpsites-[name].js',
  path: path.resolve(__dirname, 'dist', 'js')
};

/*
 * Webpack dev build
 */
function dtp_jsbuild_dev ( ) {
  var jsrc = 'client/js/index.js';
  var jdst = 'dist/js';
  return gulp
  .src(jsrc)
  .pipe(webpack({
    mode: 'development',
    devtool: webpackDevtool,
    resolve: webpackResolve,
    entry: {
      "app": './client/js/index.js',
      "admin": './client/js/index-admin.js',
    },
    output: webpackOutput,
    plugins: [
      new GenerateSW({
        swDest: 'service_worker.js',
      }),
    ],
    performance: {
      hints: false,
      maxEntrypointSize: 512 * 1024,
      maxAssetSize: 512 * 1024,
    },
  }))
  .on('error', function (err) { console.log(err.toString()); })
  .pipe(gulp.dest(jdst))
  ;
}

/*
 * Webpack prod build
 */
function dtp_jsbuild_prod ( ) {
  var jsrc = 'client/js/index.js';
  var jdst = 'dist/js';
  return gulp
  .src(jsrc)
  .pipe(webpack({
    mode: 'production',
    devtool: webpackDevtool,
    resolve: webpackResolve,
    entry: {
      "app.min": './client/js/index.js',
      "admin.min": './client/js/index-admin.js',
    },
    optimization: {
      minimize: true,
      minimizer: [new TerserPlugin({
        extractComments: true,
      })],
    },
    output: webpackOutput,
    plugins: [
      new GenerateSW({
        swDest: 'service_worker.min.js',
      }),
    ],
    performance: {
      hints: false,
      maxEntrypointSize: 512 * 1024,
      maxAssetSize: 512 * 1024,
    },
  }))
  .on('error', function (err) { console.log(err.toString()); })
  .pipe(gulp.dest(jdst))
  ;
}

function dtp_watch_client (done) {
  var files = [
    './client/less/**/*.less',
    './client/less/dtp/*.less'
  ];
  gulp.watch(files, exports.less);

  var jsfiles = [
    path.join(__dirname, '..', 'dtp', 'dtp-lib', 'client', '**', '*.js'),
    path.join(__dirname, 'client', 'js', '**', '*.js'),
  ];
  gulp.watch(jsfiles, gulp.series(
    dtp_jshint_client,  // check syntax, etc.
    gulp.parallel(
      dtp_jsbuild_dev,  // build dev webpack
      dtp_jsbuild_prod, // build prod webpack
    ),
    function reload (done) {
      browserSync.reload();
      return done();
    },
  ));

  var workerFiles = ['app/workers/*.js'];
  gulp.watch(workerFiles, dtp_jshint_workers);

  var serviceFiles = ['app/services/**/*.js'];
  gulp.watch(serviceFiles, dtp_jshint_services);

  done();
}

function dtp_develop (done) {
  var isFirst = true;
  nodemon({
    script: 'dtp-sites.js',
    verbose: false,
    watch: [
      './*.js',
      './config/**/*.js',
      'lib/**/*.js',
      'app/**/*.js',
      'app/views/**/*.pug',
      'app/templates/**/*.pug',
      'app/services/**/*.js',
      'app/workers/**/*.js',
    ],
    ext: 'js pug',
    stdout: false,
    done: done
  })
  .on('readable', function ( ) {
    this.stdout.on('data', (chunk) => {
      if (/platform online/.test(chunk)) {
        if (isFirst) {
          util_start_browsersync();
          isFirst = false;
        } else {
          browserSync.reload();
        }
      }
    });
    this.stdout.pipe(process.stdout);
    this.stderr.pipe(process.stderr);
  });
}

exports.less = gulp.series(
  dtp_less_light,
  dtp_less_dark,
);

exports.jshint = gulp.parallel(
  dtp_jshint_models,
  dtp_jshint_lib,
  dtp_jshint_controllers,
  dtp_jshint_client,
  dtp_jshint_workers,
  dtp_jshint_services,
);

exports.build = gulp.parallel(
  exports.less,
  exports.jshint,
  dtp_jsbuild_dev,
  dtp_jsbuild_prod,
);

exports.default = gulp.series(
  exports.build,
  gulp.parallel(dtp_watch_client, dtp_develop)
);
