text: 'use strict';
  
  require('module-alias/register');
  const chalk = require('chalk');
  const electron = require('electron');
  const path = require('path');
  const { say } = require('cfonts');
  const { spawn } = require('child_process');
  const webpack = require('webpack');
  const WebpackDevServer = require('webpack-dev-server');
  const webpackHotMiddleware = require('webpack-hot-middleware');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
  
  const mainConfig = require('./webpack.main.config');
  const rendererConfig = require('./webpack.renderer.config');
  const webConfig = require('./webpack.web.config');
  
  let electronProcess = null;
  let manualRestart = false;
  let hotMiddleware;
  
  function logStats(proc, data) {
    let log = '';
  
    log += chalk.yellow.bold(`┏ ${proc} Process ${new Array(19 - proc.length + 1).join('-')}`);
    log += '\n\n';
  
    if (typeof data === 'object') {
      data
        .toString({
          colors: true,
          chunks: false,
        })
        .split(/\r?\n/)
        .forEach(line => {
          log += '  ' + line + '\n';
        });
    } else {
      log += `  ${data}\n`;
    }
  
    log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n';
  
    console.log(log);
  }
  
  function startRenderer() {
    return new Promise((resolve, reject) => {
      rendererConfig.entry.index = [path.join(__dirname, 'dev-client')].concat(
        rendererConfig.entry.index,
      );
      rendererConfig.mode = 'development';
      const compiler = webpack(rendererConfig);
      hotMiddleware = webpackHotMiddleware(compiler, {
        log: false,
        heartbeat: 2500,
      });
  
      compiler.hooks.compilation.tap('compilation', compilation => {
        HtmlWebpackPlugin.getHooks(compilation).afterEmit.tapAsync(
          'html-webpack-plugin-after-emit',
          (data, cb) => {
            hotMiddleware.publish({ action: 'reload' });
            cb();
          },
        );
      });
  
      compiler.hooks.done.tap('done', stats => {
        logStats('Renderer', stats);
      });
  
      const server = new WebpackDevServer(compiler, {
        contentBase: path.join(__dirname, '../'),
        quiet: true,
        before(app, ctx) {
          app.use(hotMiddleware);
          ctx.middleware.waitUntilValid(() => {
            resolve();
          });
        },
      });
  
      server.listen(9080);
    });
  }
  
  
  
  function startWeb() {
    return new Promise((resolve, reject) => {
      webConfig.entry.index = [path.join(__dirname, 'dev-client')].concat(
        webConfig.entry.index,
      );
      webConfig.mode = 'development';
      const compiler = webpack(webConfig);
      hotMiddleware = webpackHotMiddleware(compiler, {
        log: false,
        heartbeat: 2500,
      });
  
      compiler.hooks.compilation.tap('compilation', compilation => {
        HtmlWebpackPlugin.getHooks(compilation).afterEmit.tapAsync(
          'html-webpack-plugin-after-emit',
          (data, cb) => {
            hotMiddleware.publish({ action: 'reload' });
            cb();
          },
        );
      });
  
      compiler.hooks.done.tap('done', stats => {
        logStats('Renderer', stats);
      });
  
      const server = new WebpackDevServer(compiler, {
        contentBase: path.join(__dirname, '../'),
        quiet: true,
        before(app, ctx) {
          app.use(hotMiddleware);
          ctx.middleware.waitUntilValid(() => {
            resolve();
          });
        },
      });
  
      server.listen(9081);
    });
  }
  
  function startMain() {
    return new Promise((resolve, reject) => {
      mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(
        mainConfig.entry.main,
      );
      mainConfig.mode = 'development';
      const compiler = webpack(mainConfig);
  
      compiler.hooks.watchRun.tapAsync('watch-run', (compilation, done) => {
        logStats('Main', chalk.white.bold('compiling...'));
        hotMiddleware.publish({ action: 'compiling' });
        done();
      });
  
      compiler.watch({}, (err, stats) => {
        if (err) {
          console.log(err);
          return;
        }
  
        logStats('Main', stats);
  
        if (electronProcess && electronProcess.kill) {
          manualRestart = true;
          process.kill(electronProcess.pid);
          electronProcess = null;
          startElectron();
  
          setTimeout(() => {
            manualRestart = false;
          }, 5000);
        }
  
        resolve();
      });
    });
  }
  
  function startElectron() {
    var args = ['--inspect=5858', path.join(__dirname, '../dist/electron/main.js')];
  
    // detect yarn or npm and process commandline args accordingly
    if (process.env.npm_execpath.endsWith('yarn.js')) {
      args = args.concat(process.argv.slice(3));
    } else if (process.env.npm_execpath.endsWith('npm-cli.js')) {
      args = args.concat(process.argv.slice(2));
    }
  
    electronProcess = spawn(electron, args);
  
    electronProcess.stdout.on('data', data => {
      electronLog(data, 'blue');
    });
    electronProcess.stderr.on('data', data => {
      // suppress the currently useless ERROR:CONSOLE error
      if (
        data.includes('Could not instantiate: ProductRegistryImpl.Registry') ||
        data.includes('product_registry_impl_module.js')
      ) {
        return;
      }
      electronLog(data, 'red');
    });
  
    electronProcess.on('close', () => {
      if (!manualRestart) process.exit();
    });
  }
  
  function electronLog(data, color) {
    let log = '';
    data = data.toString().split(/\r?\n/);
    data.forEach(line => {
      log += `  ${line}\n`;
    });
    if (/[0-9A-z]+/.test(log)) {
      console.log(
        chalk[color].bold('┏ Electron -------------------') +
          '\n\n' +
          log +
          chalk[color].bold('┗ ----------------------------') +
          '\n',
      );
    }
  }
  
  function greeting() {
    const cols = process.stdout.columns;
    let text = '';
  
    if (cols > 76) text = 'SPlayer';
    else text = false;
  
    if (text) {
      say(text, {
        colors: ['yellow'],
        font: 'simple3d',
        space: false,
      });
    } else console.log(chalk.yellow.bold('\n  SPlayer'));
    console.log(chalk.blue('  getting ready...') + '\n');
  }
  
  function init() {
    greeting();
  
    Promise.all([startRenderer(), startMain(), startWeb()])
      .then(() => {
        startElectron();
      })
      .catch(err => {
        console.error(err);
      });
  }
  
  init();
  