"use strict";

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

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

function _minimatch() {
  const data = _interopRequireDefault(require("minimatch"));

  _minimatch = function () {
    return data;
  };

  return data;
}

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

  _constants = function () {
    return data;
  };

  return data;
}

function _componentMap() {
  const data = _interopRequireDefault(require("../../../bit-map/component-map"));

  _componentMap = function () {
    return data;
  };

  return data;
}

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

  _bitId = function () {
    return data;
  };

  return data;
}

function _generalError() {
  const data = _interopRequireDefault(require("../../../../error/general-error"));

  _generalError = function () {
    return data;
  };

  return data;
}

function _hasWildcard() {
  const data = _interopRequireDefault(require("../../../../utils/string/has-wildcard"));

  _hasWildcard = function () {
    return data;
  };

  return data;
}

function _consumerOverrides() {
  const data = require("../../../config/consumer-overrides");

  _consumerOverrides = function () {
    return data;
  };

  return data;
}

class OverridesDependencies {
  constructor(component, consumer) {
    this.component = component;
    this.consumer = consumer; // $FlowFixMe

    this.componentMap = this.component.componentMap;
    this.componentFromModel = this.component.componentFromModel;
    this.manuallyRemovedDependencies = {};
    this.manuallyAddedDependencies = {};
  }

  shouldIgnoreFile(file, fileType) {
    const shouldIgnoreByGlobMatch = patterns => {
      return patterns.some(pattern => (0, _minimatch().default)(file, pattern));
    };

    const field = fileType.isTestFile ? 'devDependencies' : 'dependencies';
    const ignoreField = this.component.overrides.getIgnoredFiles(field);
    const ignore = shouldIgnoreByGlobMatch(ignoreField);

    if (ignore) {
      this._addManuallyRemovedDep(field, file);
    }

    return ignore;
  }

  shouldIgnorePackage(packageName, fileType) {
    const shouldIgnorePackage = packages => {
      return packages.some(pkg => pkg === packageName);
    };

    const field = fileType.isTestFile ? 'devDependencies' : 'dependencies';
    const ignoreField = this.component.overrides.getIgnoredPackages(field);
    const ignore = shouldIgnorePackage(ignoreField);

    if (ignore) {
      this._addManuallyRemovedDep(field, packageName);
    }

    return ignore;
  }

  shouldIgnorePeerPackage(packageName) {
    const shouldIgnorePackage = packages => {
      return packages.some(pkg => pkg === packageName);
    };

    const field = 'peerDependencies';
    const ignorePeer = this.component.overrides.getIgnoredPackages(field);
    const ignore = shouldIgnorePackage(ignorePeer);

    if (ignore) {
      this._addManuallyRemovedDep(field, packageName);
    }

    return ignore;
  }

  shouldIgnoreComponent(componentId, fileType) {
    const componentIdStr = componentId.toStringWithoutVersion();

    const shouldIgnore = ids => {
      return ids.some(idStr => {
        if ((0, _hasWildcard().default)(idStr)) {
          // we don't support wildcards for components for now. it gets things complicated
          // and may cause unpredicted behavior especially for imported that the originally ignored
          // wildcards interfere with legit components
          return null;
        }

        return componentId.toStringWithoutVersion() === idStr || componentId.toStringWithoutScopeAndVersion() === idStr;
      });
    };

    const field = fileType.isTestFile ? 'devDependencies' : 'dependencies';
    const ignoreField = this.component.overrides.getIgnoredComponents(field);
    const ignore = shouldIgnore(ignoreField);

    if (ignore) {
      this._addManuallyRemovedDep(field, componentIdStr);
    }

    return ignore;
  }

  getDependenciesToAddManually(packageJson, existingDependencies) {
    const overrides = this.component.overrides.componentOverridesData;
    if (!overrides) return null;
    const idsFromBitmap = this.consumer.bitMap.getAllBitIds([_constants().COMPONENT_ORIGINS.AUTHORED, _constants().COMPONENT_ORIGINS.IMPORTED]);
    const components = {};
    const packages = {};

    _consumerOverrides().dependenciesFields.forEach(depField => {
      if (!overrides[depField]) return;
      const idsFromModel = this.componentFromModel ? this.componentFromModel.dependencies.getAllIds() : new (_bitId().BitIds)();
      Object.keys(overrides[depField]).forEach(dependency => {
        const dependencyValue = overrides[depField][dependency];
        if (dependencyValue === _constants().MANUALLY_REMOVE_DEPENDENCY) return;

        const componentId = this._getComponentIdToAdd(depField, dependency, dependencyValue, idsFromBitmap, idsFromModel);

        if (componentId) {
          // $FlowFixMe
          const dependencyExist = existingDependencies[depField].find(d => d.id.isEqualWithoutScopeAndVersion(componentId));

          if (!dependencyExist) {
            this._addManuallyAddedDep(depField, componentId.toString());

            components[depField] ? components[depField].push(componentId) : components[depField] = [componentId];
          }

          return;
        }

        const addedPkg = this._manuallyAddPackage(depField, dependency, dependencyValue, packageJson);

        if (addedPkg) {
          packages[depField] = Object.assign(packages[depField] || {}, addedPkg);
        }
      });
    });

    return {
      components,
      packages
    };
  }

  _getComponentIdToAdd(field, dependency, dependencyValue, idsFromBitmap, idsFromModel) {
    if (field === 'peerDependencies') return null;
    if (!dependency.startsWith(_constants().OVERRIDE_COMPONENT_PREFIX)) return null;
    dependency = dependency.replace(_constants().OVERRIDE_COMPONENT_PREFIX, '');
    const idFromBitMap = idsFromBitmap.searchStrWithoutVersion(dependency) || idsFromBitmap.searchStrWithoutScopeAndVersion(dependency);
    const idFromModel = idsFromModel.searchStrWithoutVersion(dependency) || idsFromModel.searchStrWithoutScopeAndVersion(dependency);
    if (!idFromBitMap && !idFromModel) return null; // $FlowFixMe one of them must be set (see one line above)

    const id = idFromModel || idFromBitMap;
    return dependencyValue === _constants().MANUALLY_ADD_DEPENDENCY ? id : id.changeVersion(dependencyValue);
  }

  _manuallyAddPackage(field, dependency, dependencyValue, packageJson) {
    const packageVersionToAdd = () => {
      if (dependencyValue !== _constants().MANUALLY_ADD_DEPENDENCY) {
        return dependencyValue;
      }

      if (!packageJson) return null;

      for (const depField of _consumerOverrides().dependenciesFields) {
        if (packageJson[depField]) {
          const found = Object.keys(packageJson[depField]).find(pkg => pkg === dependency);
          if (found) return packageJson[depField][dependency];
        }
      }

      return null;
    };

    const versionToAdd = packageVersionToAdd();

    if (!versionToAdd) {
      throw new (_generalError().default)(`unable to manually add the dependency "${dependency}" into "${this.component.id.toString()}".
it's not an existing component, nor existing package`);
    }

    const packageStr = `${dependency}@${versionToAdd}`;

    this._addManuallyAddedDep(field, packageStr);

    return {
      [dependency]: versionToAdd
    };
  }

  _addManuallyRemovedDep(field, value) {
    this.manuallyRemovedDependencies[field] ? this.manuallyRemovedDependencies[field].push(value) : this.manuallyRemovedDependencies[field] = [value];
  }

  _addManuallyAddedDep(field, value) {
    this.manuallyAddedDependencies[field] ? this.manuallyAddedDependencies[field].push(value) : this.manuallyAddedDependencies[field] = [value];
  }

}

exports.default = OverridesDependencies;