'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.exportMany = exports.exportManyBareScope = undefined;

var _regenerator;

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

var _bluebird;

function _load_bluebird() {
  return _bluebird = require('bluebird');
}

/**
 * @TODO there is no real difference between bare scope and a working directory scope - let's adjust terminology to avoid confusions in the future
 * saves a component into the objects directory of the remote scope, then, resolves its
 * dependencies, saves them as well. Finally runs the build process if needed on an isolated
 * environment.
 */
var exportManyBareScope = exports.exportManyBareScope = function () {
  var _ref = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee(scope, componentsObjects) {
    var manyObjects, manyCompVersions, scopeComponentsImporter, bitIds, ids;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee$(_context) {
      while (1) {
        switch (_context.prev = _context.next) {
          case 0:
            (_logger || _load_logger()).default.debugAndAddBreadCrumb('scope.exportManyBareScope', `Going to save ${componentsObjects.length} components`);
            manyObjects = componentsObjects.map(function (componentObjects) {
              return componentObjects.toObjects(scope.objects);
            });
            _context.next = 4;
            return mergeObjects(scope, manyObjects);

          case 4:
            _context.next = 6;
            return Promise.all(manyObjects.map(function (objects) {
              return objects.component.toComponentVersion((_constants || _load_constants()).LATEST);
            }));

          case 6:
            manyCompVersions = _context.sent;

            (_logger || _load_logger()).default.debugAndAddBreadCrumb('exportManyBareScope', 'will try to importMany in case there are missing dependencies');

            scopeComponentsImporter = (_scopeComponentsImporter || _load_scopeComponentsImporter()).default.getInstance(scope);
            bitIds = (_bitId || _load_bitId()).BitIds.fromArray(manyCompVersions.map(function (compVersion) {
              return compVersion.id;
            }));
            _context.next = 12;
            return scopeComponentsImporter.importMany(bitIds, true, false);

          case 12:
            // resolve dependencies
            (_logger || _load_logger()).default.debugAndAddBreadCrumb('exportManyBareScope', 'successfully ran importMany');
            _context.next = 15;
            return scope.objects.persist();

          case 15:
            (_logger || _load_logger()).default.debugAndAddBreadCrumb('exportManyBareScope', 'objects were written successfully to the filesystem');
            ids = manyCompVersions.map(function (compVersion) {
              return compVersion.id.toString();
            });

            (_logger || _load_logger()).default.debug('exportManyBareScope: completed. exit.');
            return _context.abrupt('return', ids);

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

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

var exportMany = exports.exportMany = function () {
  var _ref2 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee3(scope, ids, remoteName) {
    var _this = this;

    var context = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
    var remotes, remote, componentObjects, componentsAndObjects, manyObjectsP, manyObjects, exportedIds, idsWithRemoteScope;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee3$(_context3) {
      while (1) {
        switch (_context3.prev = _context3.next) {
          case 0:
            (_logger || _load_logger()).default.debugAndAddBreadCrumb('scope.exportMany', 'ids: {ids}', { ids: ids.toString() });
            _context3.next = 3;
            return (0, (_scopeRemotes || _load_scopeRemotes()).getScopeRemotes)(scope);

          case 3:
            remotes = _context3.sent;
            _context3.next = 6;
            return remotes.resolve(remoteName, scope);

          case 6:
            remote = _context3.sent;
            _context3.next = 9;
            return (0, (_pMapSeries || _load_pMapSeries()).default)(ids, function (id) {
              return scope.sources.getObjects(id);
            });

          case 9:
            componentObjects = _context3.sent;
            componentsAndObjects = [];

            (0, (_enrichContextFromGlobal || _load_enrichContextFromGlobal()).default)(context);
            manyObjectsP = componentObjects.map(function () {
              var _ref3 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee2(componentObject) {
                var componentAndObject, componentBuffer, objectsBuffer;
                return (_regenerator || _load_regenerator()).default.wrap(function _callee2$(_context2) {
                  while (1) {
                    switch (_context2.prev = _context2.next) {
                      case 0:
                        componentAndObject = componentObject.toObjects(scope.objects);

                        componentAndObject.component.clearStateData();
                        convertNonScopeToCorrectScope(scope, componentAndObject, remoteName);
                        componentsAndObjects.push(componentAndObject);
                        _context2.next = 6;
                        return componentAndObject.component.compress();

                      case 6:
                        componentBuffer = _context2.sent;
                        _context2.next = 9;
                        return Promise.all(componentAndObject.objects.map(function (obj) {
                          return obj.compress();
                        }));

                      case 9:
                        objectsBuffer = _context2.sent;
                        return _context2.abrupt('return', new (_componentObjects || _load_componentObjects()).default(componentBuffer, objectsBuffer));

                      case 11:
                      case 'end':
                        return _context2.stop();
                    }
                  }
                }, _callee2, _this);
              }));

              return function (_x7) {
                return _ref3.apply(this, arguments);
              };
            }());
            _context3.next = 15;
            return Promise.all(manyObjectsP);

          case 15:
            manyObjects = _context3.sent;
            exportedIds = void 0;
            _context3.prev = 17;
            _context3.next = 20;
            return remote.pushMany(manyObjects, context);

          case 20:
            exportedIds = _context3.sent;

            (_logger || _load_logger()).default.debugAndAddBreadCrumb('exportMany', 'successfully pushed all ids to the bare-scope, going to save them back to local scope');
            _context3.next = 28;
            break;

          case 24:
            _context3.prev = 24;
            _context3.t0 = _context3['catch'](17);

            (_logger || _load_logger()).default.warnAndAddBreadCrumb('exportMany', 'failed pushing ids to the bare-scope');
            return _context3.abrupt('return', Promise.reject(_context3.t0));

          case 28:
            _context3.next = 30;
            return Promise.all(ids.map(function (id) {
              return scope.sources.removeComponentById(id);
            }));

          case 30:
            ids.map(function (id) {
              return scope.createSymlink(id, remoteName);
            });
            componentsAndObjects.map(function (componentObject) {
              return scope.sources.put(componentObject);
            });
            _context3.next = 34;
            return scope.objects.persist();

          case 34:
            idsWithRemoteScope = exportedIds.map(function (id) {
              return (_bitId || _load_bitId()).BitId.parse(id, true);
            });
            return _context3.abrupt('return', idsWithRemoteScope);

          case 36:
          case 'end':
            return _context3.stop();
        }
      }
    }, _callee3, this, [[17, 24]]);
  }));

  return function exportMany(_x3, _x4, _x5) {
    return _ref2.apply(this, arguments);
  };
}();

var mergeObjects = function () {
  var _ref4 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee5(scope, manyObjects) {
    var _this2 = this;

    var mergeResults, componentsWithConflicts, idsAndVersions, idsAndVersionsSorted;
    return (_regenerator || _load_regenerator()).default.wrap(function _callee5$(_context5) {
      while (1) {
        switch (_context5.prev = _context5.next) {
          case 0:
            _context5.next = 2;
            return Promise.all(manyObjects.map(function () {
              var _ref5 = (0, (_bluebird || _load_bluebird()).coroutine)( /*#__PURE__*/(_regenerator || _load_regenerator()).default.mark(function _callee4(objects) {
                var result;
                return (_regenerator || _load_regenerator()).default.wrap(function _callee4$(_context4) {
                  while (1) {
                    switch (_context4.prev = _context4.next) {
                      case 0:
                        _context4.prev = 0;
                        _context4.next = 3;
                        return scope.sources.merge(objects, true, false);

                      case 3:
                        result = _context4.sent;
                        return _context4.abrupt('return', result);

                      case 7:
                        _context4.prev = 7;
                        _context4.t0 = _context4['catch'](0);

                        if (!(_context4.t0 instanceof (_exceptions || _load_exceptions()).MergeConflict)) {
                          _context4.next = 11;
                          break;
                        }

                        return _context4.abrupt('return', _context4.t0);

                      case 11:
                        throw _context4.t0;

                      case 12:
                      case 'end':
                        return _context4.stop();
                    }
                  }
                }, _callee4, _this2, [[0, 7]]);
              }));

              return function (_x10) {
                return _ref5.apply(this, arguments);
              };
            }()));

          case 2:
            mergeResults = _context5.sent;
            componentsWithConflicts = mergeResults.filter(function (result) {
              return result instanceof (_exceptions || _load_exceptions()).MergeConflict;
            });

            if (!componentsWithConflicts.length) {
              _context5.next = 8;
              break;
            }

            idsAndVersions = componentsWithConflicts.map(function (c) {
              return { id: c.id, versions: c.versions };
            });
            // sort to have a consistent error message

            idsAndVersionsSorted = (_ramda || _load_ramda()).default.sortBy((_ramda || _load_ramda()).default.prop('id'), idsAndVersions);
            throw new (_exceptions || _load_exceptions()).MergeConflictOnRemote(idsAndVersionsSorted);

          case 8:
          case 'end':
            return _context5.stop();
        }
      }
    }, _callee5, this);
  }));

  return function mergeObjects(_x8, _x9) {
    return _ref4.apply(this, arguments);
  };
}();

/**
 * When exporting components with dependencies to a bare-scope, some of the dependencies may be created locally and as
 * a result their scope-name is null. Once the bare-scope gets the components, it needs to convert these scope names
 * to the bare-scope name.
 * Since the changes it does affect the Version objects, the version REF of a component, needs to be changed as well.
 */


var _ramda;

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

var _pMapSeries;

function _load_pMapSeries() {
  return _pMapSeries = _interopRequireDefault(require('p-map-series'));
}

var _enrichContextFromGlobal;

function _load_enrichContextFromGlobal() {
  return _enrichContextFromGlobal = _interopRequireDefault(require('../../hooks/utils/enrich-context-from-global'));
}

var _bitId;

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

var _logger;

function _load_logger() {
  return _logger = _interopRequireDefault(require('../../logger/logger'));
}

var _exceptions;

function _load_exceptions() {
  return _exceptions = require('../exceptions');
}

var _componentObjects;

function _load_componentObjects() {
  return _componentObjects = _interopRequireDefault(require('../component-objects'));
}

var _constants;

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

var _objects;

function _load_objects() {
  return _objects = require('../objects');
}

var _models;

function _load_models() {
  return _models = require('../models');
}

var _scopeRemotes;

function _load_scopeRemotes() {
  return _scopeRemotes = require('../scope-remotes');
}

var _scopeComponentsImporter;

function _load_scopeComponentsImporter() {
  return _scopeComponentsImporter = _interopRequireDefault(require('./scope-components-importer'));
}

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

function convertNonScopeToCorrectScope(scope, componentsObjects, remoteScope) {
  var getIdWithUpdatedScope = function getIdWithUpdatedScope(dependencyId) {
    if (dependencyId.scope) return dependencyId;
    var depId = (_models || _load_models()).ModelComponent.fromBitId(dependencyId);
    // todo: use 'load' for async and switch the foreach with map.
    var dependencyObject = scope.objects.loadSync(depId.hash());
    if (dependencyObject instanceof (_models || _load_models()).Symlink) {
      return dependencyId.changeScope(dependencyObject.realScope);
    }
    return dependencyId.changeScope(remoteScope);
  };

  var getBitIdsWithUpdatedScope = function getBitIdsWithUpdatedScope(bitIds) {
    var updatedIds = bitIds.map(function (id) {
      return getIdWithUpdatedScope(id);
    });
    return (_bitId || _load_bitId()).BitIds.fromArray(updatedIds);
  };

  componentsObjects.objects.forEach(function (object) {
    if (object instanceof (_models || _load_models()).Version) {
      var hashBefore = object.hash().toString();
      object.getAllDependencies().forEach(function (dependency) {
        dependency.id = getIdWithUpdatedScope(dependency.id);
      });
      object.flattenedDependencies = getBitIdsWithUpdatedScope(object.flattenedDependencies);
      object.flattenedDevDependencies = getBitIdsWithUpdatedScope(object.flattenedDevDependencies);
      object.flattenedCompilerDependencies = getBitIdsWithUpdatedScope(object.flattenedCompilerDependencies);
      object.flattenedTesterDependencies = getBitIdsWithUpdatedScope(object.flattenedTesterDependencies);
      var hashAfter = object.hash().toString();
      if (hashBefore !== hashAfter) {
        (_logger || _load_logger()).default.debugAndAddBreadCrumb('scope._convertNonScopeToCorrectScope', `switching {id} version hash from ${hashBefore} to ${hashAfter}`, { id: componentsObjects.component.id().toString() });
        var versions = componentsObjects.component.versions;
        Object.keys(versions).forEach(function (version) {
          if (versions[version].toString() === hashBefore) {
            versions[version] = (_objects || _load_objects()).Ref.from(hashAfter);
          }
        });
      }
    }
  });

  componentsObjects.component.scope = remoteScope;
}