#! /usr/bin/env node

const sh = require('shelljs');
const commandLineArgs = require('command-line-args');
const path = require('path');
const fs = require('fs');
const promptForBucket = require('./functions/promptForBucket');
const promptForTarget = require('./functions/promptForTarget');
const confirmDestination = require('./functions/confirmDestination');
const loadCertSettings = require('./functions/loadCertSettings');
const updateUrlsToStaging = require('./functions/updateUrlsToStaging');

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

const buckets = (pkg && pkg.config && pkg.config.aws && pkg.config.aws.buckets) ||
  ['dev-apps.enplug.in', 'apps.enplug.in', 'apps.enplug.com'];

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 isLocalOrEnplugUrl(src) {
  return (src.indexOf('//') !== 0 && src.indexOf('http') !== 0) ||
    (src.indexOf('enplug.com') >= 0) ||
    (src.indexOf('enplug.in'));
}

function extractResources(target, rx, file) {
  let match = rx.exec(file);
  while (match != null) {
    let src = match[1]
    // Add local resources and enplug.com files.
    if (isLocalOrEnplugUrl(src)) {
      target.push(src);
    }
    match = rx.exec(file);
  }
}
/**
 * Copies offline support service woker over to the application.
 */
function copyOfflineSupportWorker() {
  return new Promise((resolve) => {
    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(__dirname, './templates/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.
        extractResources(offlineConfig.staticResources, indexFile, new RegExp(/src="(.*?\.js)"/mg));
        extractResources(offlineConfig.staticResources, indexFile, new RegExp(/href="([^"]*?\.css)"/mg));

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

        fs.readFile(srcFilePath, 'utf8', (err, data) => {
          if (err) {
            console.log('Unable to read common offline file. Please check if @enplug/sdk-player is installed.');
            resolve();
            return;
          }
          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) {
              console.log('Unable to write a common offline service worker file:', err);
              resolve();
              return;
            }
          });
        });
      });
    } catch (e) {
      console.warn(`Unable to copy offline support service worker. Please check whether offline.config.json exists.`, e);
      resolve();
    }
  });
}

function runBuild() {
  const needsDevServer = options['dev-server'];
  let command = '';

  if (needsDevServer) {
    const devCert = loadCertSettings(rootPath);
    // webpack server + selected target + dev config
    command = `webpack-dev-server --https --config webpack.config.${target}.dev.js --watch --colors --inline --progress --host localhost.enplug.in --cert "${devCert.cert}" --key "${devCert.key}"`;
  } else {
    command = 'rimraf dist/' + target + // clean previous build
      ' && rimraf tmp ' + // clean tmp
      // webpack build + selected target + prod config
      ' && webpack --https --config webpack.config.' + target + '.prod.js --bail --progress --profile';
  }

  sh.exec(command, function (argument) {
    if (target === 'app') {
      copyOfflineSupportWorker();
    }
    if (target === 'app' && bucket.endsWith('enplug.in')) {
      updateUrlsToStaging(rootPath, 'dist/app', false);
    }
    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(bucket, buckets)
    .then(selectedBucket => bucket = selectedBucket)
    .then(() => promptForTarget(target, targets))
    .then(runBuild);
} else {
  promptForTarget().then(runBuild);
}
