// 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.

var Promise = require('bluebird');
var cliUtil = require('apiconnect-cli-util');
var debug = require('debug')('apiconnect-cli-apps:lib:publish:bluemix');
var f = require('util').format;
var logger = require('apiconnect-cli-logger');
var os = require('os');
var path = require('path');
var publish = require('apiconnect-cli-publish-bluemix').publish;
var prepareProject = require('apiconnect-cli-publish-bluemix').prepareProject;
var rimraf = Promise.promisify(require('rimraf'));
var fsExtra = Promise.promisifyAll(require('fs-extra'));
var mkdirp = Promise.promisify(require('mkdirp'));

var build = require('../build/build');

function bluemixPublish(providerOrg, providerApp, projectDir, hostname, projectType, versionOptions) {
  var tmpPath = path.join(os.tmpdir(), Math.random() + '-' + (+new Date()));
  var zipFilePath = path.join(tmpPath, 'package.zip');
  var tmpProjectDir = path.join(tmpPath, 'project');

  debug('tmp project dir: %s', tmpProjectDir);
  debug('zip file %s', zipFilePath);

  var preparePromise = mkdirp(tmpProjectDir).then(function() {
    logger.writeln('...preparing project');
    var filter = function(s) { return s.indexOf('node_modules') === -1; };
    return fsExtra.copyAsync(projectDir, tmpProjectDir, filter);
  }).then(function() {
    return prepareProject(tmpProjectDir, projectType);
  });

  return preparePromise.then(function() {
    logger.writeln('...building package for deploy');
    return build(tmpProjectDir, {
      zip: true,
      install: false,
      scripts: false,
      outputFilePath: zipFilePath,
      embedPackageDir: false,
    });
  }).then(function() {
    var publishOpts = {
      hostname: hostname,
      org: providerOrg.bluemix.organization,
      space: providerOrg.bluemix.space,
      app: providerApp.name,
      region: providerOrg.bluemix.inviteUri,
      providerOrg: providerOrg.name,
      zip: zipFilePath,
      ui: true,
      versionOptions: versionOptions,
    };
    debug('invoking bluemix publish with %j', publishOpts);
    logger.writeln('...uploading package');
    return publish(publishOpts).then(function(publishInfo) {
      debug('%j', publishInfo);

      // Only looking for 200/201 right now. Other 2xx codes are not expected
      if (publishInfo.statusCode !== 200 && publishInfo.statusCode !== 201) {
        var err = new Error('Unable to publish to Bluemix.');
        err.details = publishInfo;
        throw err;
      }

      if (publishInfo.body.staging_failed_description || publishInfo.body.staging_failed_reason) {
        throw new Error(f(
          'Unable to publish to Bluemix.\n%s\n%s',
          publishInfo.body.staging_failed_reason, publishInfo.body.staging_failed_description
        ));
      }

      var res = {
        hostname: '',
        managementUri: '',
        runtimeAppId: '',
        extendedStatus: publishInfo,
        messages: [],
      };
      if (publishInfo && publishInfo.body) {
        var body = publishInfo.body;
        if (body.routes && body.routes[0]) { //should check for body.runtimeEndpoint
          res.hostname = body.routes[0].host + '.' + body.routes[0].domain.name;
        }
        res.managementUri = publishInfo.runtimeUrl;
        res.runtimeAppId = body.guid;
        res.messages.push(publishInfo.message + '\n');
        if (body.detected_buildpack) {
          res.messages.push(f('Using buildpack: %s', body.detected_buildpack));
        }
        res.messages.push(f('Management URL: %s', res.managementUri));

        if (res.hostname) {
          res.messages.push(f('API target urls: %s', res.hostname));
        }
        res.messages = res.messages.concat(preparePromise.value());
      }

      return rimraf(tmpPath, { glob: false }).catch(function(err) {
        logger.debug('Unable to remove tmpdir %s: %s', tmpPath, err.message);
      }).then(function() {
        return res;
      });
    });
  }).then(function updateProviderApp(res) {
    return cliUtil.ProviderApps.update({
      server: hostname,
      org: providerOrg.id,
      app: providerApp.name,
      data: {
        bluemix: {
          applicationUrl: res.managementUri,
        },
      },
    }).then(function() {
      return res;
    });
  });
}
module.exports = bluemixPublish;
