'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _regenerator;

function _load_regenerator() {
  return _regenerator = _interopRequireDefault(require('babel-runtime/regenerator'));
}

var _fsExtra;

function _load_fsExtra() {
  return _fsExtra = _interopRequireDefault(require('fs-extra'));
}

var _glob;

function _load_glob() {
  return _glob = _interopRequireDefault(require('glob'));
}

var _ramda;

function _load_ramda() {
  return _ramda = _interopRequireDefault(require('ramda'));
}

var _path;

function _load_path() {
  return _path = _interopRequireDefault(require('path'));
}

var _semver;

function _load_semver() {
  return _semver = _interopRequireDefault(require('semver'));
}

var _consumer;

function _load_consumer() {
  return _consumer = require('../../../consumer');
}

var _loader;

function _load_loader() {
  return _loader = _interopRequireDefault(require('../../../cli/loader'));
}

var _loaderMessages;

function _load_loaderMessages() {
  return _loaderMessages = require('../../../cli/loader/loader-messages');
}

var _flattenDependencies;

function _load_flattenDependencies() {
  return _flattenDependencies = require('../../../scope/flatten-dependencies');
}

var _constants;

function _load_constants() {
  return _constants = require('../../../constants');
}

var _bitId;

function _load_bitId() {
  return _bitId = require('../../../bit-id');
}

var _analytics;

function _load_analytics() {
  return _analytics = require('../../../analytics/analytics');
}

var _generalError;

function _load_generalError() {
  return _generalError = _interopRequireDefault(require('../../../error/general-error'));
}

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

var key = (_ramda || _load_ramda()).default.compose((_ramda || _load_ramda()).default.head, (_ramda || _load_ramda()).default.keys);

exports.default = function () {
  var _ref = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(environmentOptions, importOptions, packageManagerArgs) {
    var importEnvironment = function () {
      var _ref2 = _asyncToGenerator( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(consumer) {
        var idToImport, envDependencies, id, writeToBitJsonIfNeeded;
        return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                writeToBitJsonIfNeeded = function writeToBitJsonIfNeeded() {
                  if (environmentOptions.compiler) {
                    consumer.bitJson.compiler = id;
                    (_analytics || _load_analytics()).Analytics.setExtraData('build_env', id);
                    return consumer.bitJson.write({ bitDir: consumer.getPath() });
                  }

                  if (environmentOptions.tester) {
                    consumer.bitJson.tester = id;
                    (_analytics || _load_analytics()).Analytics.setExtraData('test_env', id);
                    return consumer.bitJson.write({ bitDir: consumer.getPath() });
                  }

                  if (environmentOptions.extension) {
                    var idWithoutVersion = (_bitId || _load_bitId()).BitId.getStringWithoutVersion(id);
                    // don't create the same extension twice - check if older version exists and override it
                    var oldVersion = Object.keys(consumer.bitJson.extensions).find(function (ext) {
                      return (_bitId || _load_bitId()).BitId.getStringWithoutVersion(ext) === idWithoutVersion;
                    });
                    if (oldVersion) {
                      consumer.bitJson.extensions[id] = consumer.bitJson.extensions[oldVersion];
                      delete consumer.bitJson.extensions[oldVersion];
                      return consumer.bitJson.write({ bitDir: consumer.getPath() });
                    }
                    consumer.bitJson.extensions[id] = {
                      options: {},
                      config: {}
                    };
                    return consumer.bitJson.write({ bitDir: consumer.getPath() });
                  }

                  return Promise.resolve(true);
                };

                (_loader || _load_loader()).default.start((_loaderMessages || _load_loaderMessages()).BEFORE_IMPORT_ENVIRONMENT);

                if (importOptions.ids.length) {
                  _context.next = 4;
                  break;
                }

                throw new (_generalError || _load_generalError()).default('you must specify component id for importing an environment');

              case 4:
                idToImport = importOptions.ids[0];
                _context.next = 7;
                return consumer.importEnvironment(idToImport, importOptions.verbose, true);

              case 7:
                envDependencies = _context.sent;

                if (envDependencies.length) {
                  _context.next = 10;
                  break;
                }

                throw new (_generalError || _load_generalError()).default(`the environment component ${idToImport} is installed already`);

              case 10:
                id = envDependencies[0].component.id.toString();
                _context.next = 13;
                return writeToBitJsonIfNeeded();

              case 13:
                return _context.abrupt('return', { envDependencies });

              case 14:
              case 'end':
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

      return function importEnvironment(_x4) {
        return _ref2.apply(this, arguments);
      };
    }();

    var consumer, _ref3, dependencies, envDependencies, importDetails, bitIds, notAuthored, notAuthoredBitIds, warnings;

    return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
      while (1) {
        switch (_context2.prev = _context2.next) {
          case 0:
            _context2.next = 2;
            return (0, (_consumer || _load_consumer()).loadConsumer)();

          case 2:
            consumer = _context2.sent;

            consumer.packageManagerArgs = packageManagerArgs;

            if (!(environmentOptions.tester || environmentOptions.compiler || environmentOptions.extension)) {
              _context2.next = 6;
              break;
            }

            return _context2.abrupt('return', importEnvironment(consumer));

          case 6:
            _context2.next = 8;
            return consumer.importComponents(importOptions);

          case 8:
            _ref3 = _context2.sent;
            dependencies = _ref3.dependencies;
            envDependencies = _ref3.envDependencies;
            importDetails = _ref3.importDetails;
            bitIds = dependencies.map((_ramda || _load_ramda()).default.path(['component', 'id']));

            notAuthored = function notAuthored(bitId) {
              var componentMap = consumer.bitMap.getComponent(bitId);
              return componentMap && componentMap.origin !== (_constants || _load_constants()).COMPONENT_ORIGINS.AUTHORED;
            };

            notAuthoredBitIds = (_ramda || _load_ramda()).default.filter(notAuthored, bitIds);

            if ((_ramda || _load_ramda()).default.isEmpty(notAuthoredBitIds)) {
              _context2.next = 18;
              break;
            }

            _context2.next = 18;
            return consumer.bitJson.addDependencies(notAuthoredBitIds).write({ bitDir: consumer.getPath() });

          case 18:
            _context2.next = 20;
            return warnForPackageDependencies({
              dependencies: (0, (_flattenDependencies || _load_flattenDependencies()).flattenDependencies)(dependencies),
              envDependencies,
              consumer,
              installNpmPackages: importOptions.installNpmPackages
            });

          case 20:
            warnings = _context2.sent;

            (_analytics || _load_analytics()).Analytics.setExtraData('num_components', bitIds.length);
            _context2.next = 24;
            return consumer.onDestroy();

          case 24:
            return _context2.abrupt('return', { dependencies, envDependencies, importDetails, warnings });

          case 25:
          case 'end':
            return _context2.stop();
        }
      }
    }, _callee2, this);
  }));

  function importAction(_x, _x2, _x3) {
    return _ref.apply(this, arguments);
  }

  return importAction;
}();

// TODO: refactor to better use of semver
// TODO: move to bit-javascript


var getSemverType = function getSemverType(str) {
  if ((_semver || _load_semver()).default.valid(str)) return 'V'; // VALID_VERSION
  if ((_semver || _load_semver()).default.validRange(str)) return 'R'; // RANGE_VERSIONS
  return null;
};

// TODO: refactor to better use of semver
// TODO: move to bit-javascript
function compatibleWith(a, b) {
  var depName = key(a);
  if (!b[depName]) return false; // dependency does not exist - return false
  var bVersion = b[depName];
  var aVersion = a[depName];
  var aType = getSemverType(aVersion);
  var bType = getSemverType(bVersion);
  if (!aType || !bType) return false; // in case one of the versions is invalid - return false
  if (aType === 'V' && bType === 'V') {
    return (_semver || _load_semver()).default.eq(aVersion, bVersion);
  }
  if (aType === 'V' && bType === 'R') {
    return (_semver || _load_semver()).default.satisfies(aVersion, bVersion);
  }
  if (aType === 'R' && bType === 'V') {
    return (_semver || _load_semver()).default.satisfies(bVersion, aVersion);
  }
  if (aType === 'R' && bType === 'R') {
    if (aVersion.startsWith('^') && bVersion.startsWith('^')) {
      var aMajorVersion = parseInt(aVersion[1], 10);
      var bMajorVersion = parseInt(bVersion[1], 10);
      if (aMajorVersion === bMajorVersion) return true;
    }
  }
  return false;
}

// TODO: refactor to better use of semver
// TODO: move to bit-javascript
var warnForPackageDependencies = function warnForPackageDependencies(_ref4) {
  var dependencies = _ref4.dependencies,
      consumer = _ref4.consumer,
      installNpmPackages = _ref4.installNpmPackages;

  var warnings = {
    notInPackageJson: [],
    notInNodeModules: [],
    notInBoth: []
  };
  if (installNpmPackages) return Promise.resolve(warnings);
  var projectDir = consumer.getPath();
  var getPackageJson = function getPackageJson(dir) {
    try {
      return (_fsExtra || _load_fsExtra()).default.readJSONSync((_path || _load_path()).default.join(dir, 'package.json'));
    } catch (e) {
      return {};
    } // do we want to inform the use that he has no package.json
  };
  var packageJson = getPackageJson(projectDir);
  var packageJsonDependencies = (_ramda || _load_ramda()).default.merge(packageJson.dependencies || {}, packageJson.devDependencies || {});

  var getNameAndVersion = function getNameAndVersion(pj) {
    return { [pj.name]: pj.version };
  };
  var nodeModules = (_ramda || _load_ramda()).default.mergeAll((_glob || _load_glob()).default.sync((_path || _load_path()).default.join(projectDir, 'node_modules', '*')).map((_ramda || _load_ramda()).default.compose(getNameAndVersion, getPackageJson)));

  dependencies.forEach(function (dep) {
    //eslint-disable-line
    if (!dep.packageDependencies || (_ramda || _load_ramda()).default.isEmpty(dep.packageDependencies)) return null;

    (_ramda || _load_ramda()).default.forEachObjIndexed(function (packageDepVersion, packageDepName) {
      var packageDep = { [packageDepName]: packageDepVersion };
      var compatibleWithPackgeJson = compatibleWith(packageDep, packageJsonDependencies);
      var compatibleWithNodeModules = compatibleWith(packageDep, nodeModules);

      if (!compatibleWithPackgeJson && !compatibleWithNodeModules && !(_ramda || _load_ramda()).default.contains(packageDep, warnings.notInBoth)) {
        warnings.notInBoth.push(packageDep);
      }

      if (!compatibleWithPackgeJson && compatibleWithNodeModules && !(_ramda || _load_ramda()).default.contains(packageDep, warnings.notInPackageJson)) {
        warnings.notInPackageJson.push(packageDep);
      }

      if (compatibleWithPackgeJson && !compatibleWithNodeModules && !(_ramda || _load_ramda()).default.contains(packageDep, warnings.notInNodeModules)) {
        warnings.notInNodeModules.push(packageDep);
      }
    }, dep.packageDependencies);
  });

  // Remove duplicates warnings for missing packages
  warnings.notInBoth = (_ramda || _load_ramda()).default.uniq(warnings.notInBoth);

  return Promise.resolve(warnings);
};