// 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 _ = require('lodash');
var cliConfig = require('apiconnect-cli-config');
var debug = require('debug')('apiconnect-cli-apps:lib:deploy');
var f = require('util').format;
var logger = require('apiconnect-cli-logger');
var path = require('path');
var libertyPublish = require('./publish/liberty-publish');
var bluemixPublish = require('./publish/bluemix-publish');
var cliUtil = require('apiconnect-cli-util');

/**
 * @typedef RuntimeInfo
 * @type Object
 * @property {string} hostname Hostname for the application.
 * @property {string} [header] Optional header that must be set to route to the application.
 * @property {string} managementUri URL for managing the application runtime.
 * @property {object} extendedStatus Full output from runtime deployer
 */

/**
 * Deploy project to runtime service.
 *
 * @param {object} [options] options.
 * @param {string} [options.projectDir] Directory to project files. Defaults to process.cwd()
 * @param {string} [options.server] API Management server.
 * @param {string} [options.organization] Provider org name.
 * @param {string} [options.app] Application name. Defaults to project name if available.
 * @param {string} [options.title] Application title. Defaults to application name.
 *
 * @returns {RuntimeInfo}
 */
function deployProject(options) {
  options = options || {};
  options.projectDir = options.projectDir || process.cwd();
  options = options || {};
  debug('project dir: %s', options.projectDir);
  var dirInfo = cliConfig.inspectPath(options.projectDir, { incNodeProjects: true });
  debug('inspect %j', dirInfo);

  if (dirInfo.type === 'project') {
    options.packageName = dirInfo.name;
    options.projectType = dirInfo.projectType;

    var config = cliConfig.loadConfig();
    var app = config.getOne('app') || { data: {} };
    options.server = options.server || app.hostname;
    options.organization = options.organization || app.data.orgs;
    options.app = options.app || app.data.apps || options.packageName;
    options.title = options.title || options.app || app.data.apps || options.packageName;

    return lookupRuntimeProviderOrgAndApp(options).then(function(info) {
      debug('lookup info', info);
      var providerOrg = info[0];
      var providerApp = info[1];

      if (!providerOrg) {
        throw new Error(f('The organization %s is not found.', options.organization));
      }

      if (!providerApp) {
        throw new Error(f('The application %s is not found.', options.app));
      }

      if (providerApp.bluemix) {
        logger.writeln('Deploying to Bluemix');
        return bluemixPublish(
          providerOrg, providerApp, path.resolve(options.projectDir), options.server, options.projectType,
          options.versionOptions
        ).then(function(res) {
          _.each(res.messages, function(m) {
            logger.writeln(m);
          });
          return res;
        });
      } else if (providerApp.liberty) {
        return libertyPublish(
          options.server, providerOrg, providerApp, path.resolve(options.projectDir), options.projectType
        ).then(function(res) {
          logger.writeln();
          logger.writeln('Upload to liberty server completed successfully.');
          logger.writeln('Applications may take a few minutes to update and start.');
          logger.writeln();
          logger.writeln(
            'Collectives admin center: https://%s:%s/adminCenter.',
            res.liberty.controllerHosts[0].host,
            res.liberty.controllerHosts[0].port
          );
          logger.writeln();

          var pkgJson = require(path.resolve(options.projectDir, 'package.json'));
          var isGateway = pkgJson.APIConnectGateway;
          if (!isGateway) {
            logger.writeln('Please update your swagger with:');
            logger.writeln('API target urls: %s', res.ihsInfo.join(', '));
            logger.writeln('host header: %s', res.liberty.vHostHeader);
          }
        });
      }
      throw new Error(f('The application %s with the organization %s is not found.',
        options.app, options.organization));
    });
  } else {
    throw new Error(f('The path %s is not an API Connect project.', options.projectDir));
  }
}
exports.deployProject = deployProject;

function lookupRuntimeProviderOrgAndApp(options) {
  var server = options.server;
  var orgName = options.organization;
  var appName = options.app;
  var appTitle = options.title;
  debug(server, orgName, appName);

  if (!server) {
    throw new Error('The --server option is required.');
  }

  if (!orgName) {
    throw new Error('The --organization option is required.');
  }

  var providerOrgPromise = cliUtil.Orgs.findOrgByNameAsync(server, orgName);

  var providerAppPromise = providerOrgPromise.then(function(providerOrg) {
    return cliUtil.ProviderApps.get({ server: server, org: providerOrg.id, app: appName }).catch(function(err) {
      if (err.status === 404) {
        // make a new provider-app if this is bluemix
        if (providerOrg.bluemix) {
          return cliUtil.ProviderApps.create({
            app: appName,
            title: appTitle,
            server: server,
            org: providerOrg.id,
            runtime: 'bluemix',
          });
        }
        return null;
      }
      throw err;
    });
  });

  return Promise.all([ providerOrgPromise, providerAppPromise ]);
}
