#! /usr/bin/env node

const inquirer = require('inquirer');
const sh = require('shelljs');
const commandLineArgs = require('command-line-args');
const buckets = ['apps.enplug.in', 'apps.enplug.com'];
const path = require('path');
const fs = require('fs');

const rootPath = __dirname.split('node_modules')[0];
const packagePath = rootPath + 'package.json';
const pkg = require(packagePath);

const optionDefinitions = [
  { name: 'build-for-release', alias: 'r', type: Boolean },
  { name: 'dev-server', alias: 's', type: Boolean },
  { name: 'dev', alias: 'd', type: Boolean },
  { name: 'target', alias: 't', type: String },
  { name: 'targets', type: String, multiple: true},
  { name: 'version', alias: 'v', type: String }
];

const options = commandLineArgs(optionDefinitions);
const version = options.dev ? pkg.version_dev : pkg.version;
const destination = options.dev ? `${pkg.config.destination}/dev` : pkg.config.destination;

let target = options['target']; // app or dashboard
let targets = options.targets ? options.targets : ['app', 'dashboard'];
let bucket = ''; // s3 bucket apps.enplug.in or apps.enplug.com

function promptForBucket() {
  if (!bucket) {
    return inquirer
      .prompt({
        message: 'Which bucket do you want to use?',
        name: 's3Bucket',
        type: 'list',
        choices: buckets
      })
      .then((answer) => {
        bucket = answer.s3Bucket;
        return bucket;
      });
  } else {
    return Promise.resolve(bucket);
  }
}


/**
 * If target is not defined, asks user to select one from the list.
 * @returns {Promise<string>}
 */
function promptForTarget() {
  if (!target) {
    return inquirer.prompt({
      message: 'Which target do you want to build?',
      name: 'target',
      type: 'list',
      choices: targets
    }).then((answer) => {
      target = answer.target;
      return target;
    });
  } else {
    return Promise.resolve(target);
  }
}


function confirmDestination(bucket, prefix) {
  return inquirer.prompt({
    message: `Confirm destination: "${bucket}/${prefix}"`,
    name: 'confirm',
    type: 'confirm'
  });
}



/**
 * Updates all instances of enplug.com found in index.html to enplug.in.
 */
function updateUrlsToStaging() {
  try {
    let indexFilePath = path.join(rootPath, 'dist/app/index.html');

    fs.readFile(indexFilePath, 'utf8', (err, data) => {
      if (err) {
        return console.log('Unable to find index.html file at: ', indexFilePath);
      }
      data = data.replace(/enplug\.com/ig, 'enplug.in');
      fs.writeFile(indexFilePath, data, 'utf8', (err) => {
        if (err) {
          return console.log('Unable to replace enplug.com with enplug.in:', err);
        }
      });
    });
  } catch (e) {
      console.error(e);
  }
}


/**
 * Copies offline support service woker over to the application.
 */
function copyOfflineSupportWorker() {
  try {
    const commonStaticResources = [
      '.',
      './',
      './index.html',
      './enplug-offline-worker.js'
    ];
    let indexFilePath = path.join(rootPath, 'dist/app/index.html');
    let configPath = path.join(rootPath, 'offline.config.json');
    let srcFilePath = path.join(rootPath, 'node_modules/@enplug/sdk-player/src/lib/enplug-offline-worker.js');
    let destFilePath = path.join(rootPath, 'dist/app/enplug-offline-worker.js');
    let offlineConfig = require(configPath);
    offlineConfig.appName = `${pkg.name}`;
    offlineConfig.cacheVersion = `${pkg.name}-${pkg.version.replace(/\./g, '-')}`;

    offlineConfig.staticResources = offlineConfig.staticResources || [];
    offlineConfig.staticResources = offlineConfig.staticResources.concat(commonStaticResources).sort();
    offlineConfig.staticResources = offlineConfig.staticResources.filter(function (item, position) {
      return offlineConfig.staticResources.indexOf(item) === position;
    });
    offlineConfig.noCacheUrls = offlineConfig.noCacheUrls || [];

    fs.readFile(indexFilePath, 'utf8', (err, indexFile) => {
      // Generate .css and .js static resources array.
      const reJs = new RegExp(/src="(.*?\.js)"/mg);
      const reCss = new RegExp(/href="([^"]*?\.css)"/mg);

      let srcJsMatch = reJs.exec(indexFile);
      while (srcJsMatch != null) {
        let src = srcJsMatch[1]
        // Add local resources and enplug.com files.
        if ((src.indexOf('//') !== 0 && src.indexOf('http') !== 0) ||
            (src.indexOf('enplug.com') >= 0) ||
            (src.indexOf('enplug.in'))) {
          offlineConfig.staticResources.push(src);
        }
        srcJsMatch = reJs.exec(indexFile);
      }

      let srcCssMatch = reCss.exec(indexFile);
      while (srcCssMatch != null) {
        let src = srcCssMatch[1]
        // Add local resources and enplug.com files.
        if ((src.indexOf('//') !== 0 && src.indexOf('http') !== 0) ||
            (src.indexOf('enplug.com') >= 0) ||
            (src.indexOf('enplug.in'))) {
          offlineConfig.staticResources.push(src);
        }
        srcCssMatch = reCss.exec(indexFile);
      }

      console.log('Following static resources have been found:\n', offlineConfig.staticResources);

      fs.readFile(srcFilePath, 'utf8', (err, data) => {
        if (err) {
          return console.log('Unable to read common offline file. Please check if @enplug/sdk-player is installed.');
        }
        data = data.replace(/<% config %>/g, JSON.stringify(offlineConfig));
        var offlineServiceWorkerFile = data.replace(/<% app_name %>/g, pkg.name);
        fs.writeFile(destFilePath, offlineServiceWorkerFile, 'utf8', (err) => {
           if (err) {
             return console.log('Unable to write a common offline service worker file:', err);
           }
        });
      });
    });
  } catch (e) {
    console.warn(`Unable to copy offline support service worker. Please check whether offline.config.json exists.`, e);
  }
}


function runBuild() {
  const needsDevServer = options['dev-server'];
  let command = ''
  if (!needsDevServer) {
    command += 'rimraf dist/' + target // clean previous build
    command += ' &&rimraf tmp ' // clean tmp
    command += ' && '
  }
  command += ' ' + (needsDevServer ? 'webpack-dev-server' : 'webpack'); // webpack server or regular webpack?
  command += ' --config webpack.config.' + target + '.' + (needsDevServer ? 'dev' : 'prod') + '.js '; // proper config, proper target
  command += needsDevServer ? ' --watch --colors --inline --progress --host 0.0.0.0 ' : ' --bail --progress --profile ';

  sh.exec(command, function (argument) {
    copyOfflineSupportWorker();
    if (target === 'app' && bucket.endsWith('enplug.in')) {
      updateUrlsToStaging();
    }
    if (options['build-for-release']) {
      let prefix = `${destination}/${target}/${version}`;
      confirmDestination(bucket, prefix).then(function (response) {
        if (response.confirm) {
          sh.exec(`enplug-release-app-legacy --bucket=${bucket} --prefix=${prefix} --root=${rootPath} --target=${target} --version=${version}`)
        }
      });
    }
  });
}


if (options['build-for-release']) {
  promptForBucket()
    .then(promptForTarget)
    .then(runBuild);
} else {
  promptForTarget().then(runBuild);
}
