"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _bluebird() {
  const data = require("bluebird");

  _bluebird = function () {
    return data;
  };

  return data;
}

function _defineProperty2() {
  const data = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

  _defineProperty2 = function () {
    return data;
  };

  return data;
}

function _ramda() {
  const data = _interopRequireDefault(require("ramda"));

  _ramda = function () {
    return data;
  };

  return data;
}

function _pMapSeries() {
  const data = _interopRequireDefault(require("p-map-series"));

  _pMapSeries = function () {
    return data;
  };

  return data;
}

function _removedComponents() {
  const data = require("../removed-components");

  _removedComponents = function () {
    return data;
  };

  return data;
}

function _logger() {
  const data = _interopRequireDefault(require("../../logger/logger"));

  _logger = function () {
    return data;
  };

  return data;
}

function _bitId() {
  const data = require("../../bit-id");

  _bitId = function () {
    return data;
  };

  return data;
}

function _constants() {
  const data = require("../../constants");

  _constants = function () {
    return data;
  };

  return data;
}

function _models() {
  const data = require("../models");

  _models = function () {
    return data;
  };

  return data;
}

function _scope() {
  const data = _interopRequireDefault(require("../scope"));

  _scope = function () {
    return data;
  };

  return data;
}

class RemoveModelComponents {
  constructor(scope, bitIds, force, removeSameOrigin, consumer) {
    (0, _defineProperty2().default)(this, "removeSameOrigin", false);
    this.scope = scope;
    this.bitIds = bitIds;
    this.force = force;
    this.removeSameOrigin = removeSameOrigin;
    this.consumer = consumer;
  }

  remove() {
    var _this = this;

    return (0, _bluebird().coroutine)(function* () {
      const {
        missingComponents,
        foundComponents
      } = yield _this.scope.filterFoundAndMissingComponents(_this.bitIds);
      const dependentBits = yield _this.scope.findDependentBits(foundComponents);

      if (_ramda().default.isEmpty(dependentBits) || _this.force) {
        // do not run this in parallel (promise.all), otherwise, it may throw an error when
        // trying to delete the same file at the same time (happens when removing a component with
        // a dependency and the dependency itself)
        const removedComponents = yield (0, _pMapSeries().default)(foundComponents, bitId => _this._removeSingle(bitId));
        yield _this.scope.objects.persist();
        const ids = new (_bitId().BitIds)(...removedComponents.map(x => x.bitId));
        const removedDependencies = new (_bitId().BitIds)(..._ramda().default.flatten(removedComponents.map(x => x.removedDependencies)));
        return new (_removedComponents().RemovedObjects)({
          removedComponentIds: ids,
          missingComponents,
          removedDependencies
        });
      } // some of the components have dependents, don't remove them


      return new (_removedComponents().RemovedObjects)({
        missingComponents,
        dependentBits
      });
    })();
  }
  /**
   * removeSingle - remove single component
   * @param {BitId} bitId - list of remote component ids to delete
   * @param {boolean} removeSameOrigin - remove component dependencies from same origin
   */


  _removeSingle(bitId) {
    var _this2 = this;

    return (0, _bluebird().coroutine)(function* () {
      _logger().default.debug(`scope.removeSingle ${bitId.toString()}, remove dependencies: ${_this2.removeSameOrigin.toString()}`); // $FlowFixMe


      const component = (yield _this2.scope.getModelComponentIfExist(bitId)).toComponentVersion();
      const consumerComponentToRemove = yield component.toConsumer(_this2.scope.objects); // $FlowFixMe

      const componentList = yield _this2.scope.listIncludesSymlinks();
      const dependentBits = yield _this2.scope.findDependentBits(consumerComponentToRemove.flattenedDependencies, bitId.version !== _constants().LATEST_BIT_VERSION);
      const removedDependencies = yield _this2._removeComponentsDependencies(dependentBits, componentList, consumerComponentToRemove, bitId);
      yield _this2._removeComponent(bitId, componentList);
      const version = Object.keys(component.component.versions).length <= 1 ? _constants().LATEST_BIT_VERSION : bitId.version;
      return {
        bitId: bitId.changeVersion(version),
        removedDependencies
      };
    })();
  }

  _removeComponentsDependencies(dependentBits, componentList, consumerComponentToRemove, bitId) {
    var _this3 = this;

    return (0, _bluebird().coroutine)(function* () {
      const removedComponents = consumerComponentToRemove.flattenedDependencies.map(
      /*#__PURE__*/
      function () {
        var _ref = (0, _bluebird().coroutine)(function* (dependencyId) {
          const dependentsIds = dependentBits[dependencyId.toStringWithoutVersion()];

          const relevantDependents = _ramda().default.reject(dependent => dependent.isEqual(bitId) || dependent.scope !== dependencyId.scope, dependentsIds);

          let isNested = true;

          if (_this3.consumer) {
            const componentMap = _this3.consumer.bitMap.getComponentIfExist(dependencyId);

            if (componentMap && componentMap.origin !== _constants().COMPONENT_ORIGINS.NESTED) {
              isNested = false;
            }
          }

          if (_ramda().default.isEmpty(relevantDependents) && !_this3.bitIds.searchWithoutVersion(dependencyId) && ( // don't delete dependency if it is already deleted as an individual
          dependencyId.scope !== bitId.scope || _this3.removeSameOrigin) && isNested) {
            yield _this3._removeComponent(dependencyId, componentList);
            return dependencyId;
          }

          return null;
        });

        return function (_x) {
          return _ref.apply(this, arguments);
        };
      }());
      let removedDependencies = yield Promise.all(removedComponents);
      removedDependencies = removedDependencies.filter(x => !_ramda().default.isNil(x));
      return _bitId().BitIds.fromArray(removedDependencies);
    })();
  }

  _removeComponent(id, componentList) {
    var _this4 = this;

    return (0, _bluebird().coroutine)(function* () {
      const symlink = componentList.filter(component => component instanceof _models().Symlink && id.isEqualWithoutScopeAndVersion(component.toBitId()));
      yield _this4.scope.sources.removeComponentById(id);
      if (!_ramda().default.isEmpty(symlink)) _this4.scope.objects.removeObject(symlink[0].hash());
    })();
  }

}

exports.default = RemoveModelComponents;