// Copyright IBM Corp. 2016. All Rights Reserved.
// Node module: apiconnect-cli-apps
// US Government Users Restricted Rights - Use, duplication or disclosure
// restricted by GSA ADP Schedule Contract with IBM Corp.

'use strict';

var Promise = require('bluebird');
var _ = require('lodash');
var apicConfig = require('apiconnect-cli-config');
var debug = require('debug')('apiconnect-cli-apps:lib:build:build');
var exec = require('child_process').exec;
var fmt = require('util').format;
var mkdirp = Promise.promisify(require('mkdirp'));
var pack = Promise.promisify(require('./pack'));
var path = require('path');

// liberty & local run
var defaults = { zip: false, install: true, scripts: true, outputFilePath: null, embedPackageDir: true };

module.exports = function(dir, opts) {
  opts = _.defaults(opts, defaults);
  debug(opts);

  if (!opts.install && opts.scripts) {
    return Promise.reject(new Error('The --scripts option can be used when `npm install` is enabled.'));
  }
  try {
    var projectInfo = apicConfig.inspectPath(dir, { incNodeProjects: true });
    if (projectInfo.type !== 'project') {
      return Promise.reject(new Error(fmt('The path %s is not an API Connect project.', dir)));
    }
  } catch (err) {
    debug(err);
    return Promise.reject(err);
  }
  var packageJson = require(path.resolve('package.json'));

  return Promise.reduce(buildCommands(), function(result, fn) {
    result = fn();
    return result;
  }, {}).then(function(result) {
    debug('done building', result);
    return result;
  });

  function buildCommands() {
    var cmds = [];
    if (opts.install) {
      var installCmd = 'npm install --production';
      if (!opts.scripts) {
        installCmd += ' --ignore-scripts';
      }
      cmds.push(cmdWrapper(installCmd));
      if (opts.scripts && packageJson.scripts && packageJson.scripts.build) {
        cmds.push(cmdWrapper('npm run build'));
      }
    }
    cmds.push(cmdWrapper('npm prune --production'));
    cmds.push(runPack(opts.zip));

    return cmds;
  }

  function cmdWrapper(cmdStr) {
    debug('schedule %s', cmdStr);
    return function() {
      debug('executing %s > %s', dir, cmdStr);
      return new Promise(function(resolve, reject) {
        try {
          exec(cmdStr, { cwd: dir }, function(err, stdout, stderr) {
            debug(stdout);
            debug(stderr);
            if (err) {
              return reject(err);
            }
            return resolve(stdout);
          });
        } catch (err) {
          return reject(err);
        }
      });
    };
  }

  function runPack(zip) {
    debug('schedule runPack');
    return function() {
      var fileName = fmt('%s-%s.%s', packageJson.name, packageJson.version, zip ? 'zip' : 'tgz');
      var dst = opts.outputFilePath || path.join(dir, '..', fileName);
      debug('packing into', dst);
      return mkdirp(path.dirname(dst)).then(function() {
        debug('mkdirp done');
        return pack(dir, dst, zip ? 'zip' : 'tgz', opts.embedPackageDir).then(function() {
          debug('packing completed', dst);
          return dst;
        });
      });
    };
  }
};
