"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.statesFilter = exports.Filter = void 0;
function _componentId() {
  const data = require("@teambit/component-id");
  _componentId = function () {
    return data;
  };
  return data;
}
function _pMapSeries() {
  const data = _interopRequireDefault(require("p-map-series"));
  _pMapSeries = function () {
    return data;
  };
  return data;
}
function _lodash() {
  const data = require("lodash");
  _lodash = function () {
    return data;
  };
  return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const statesFilter = exports.statesFilter = ['new', 'modified', 'deprecated', 'deleted', 'snappedOnMain', 'softTagged', 'codeModified', 'localOnly'];
class Filter {
  constructor(workspace) {
    this.workspace = workspace;
  }
  async by(criteria, ids) {
    return criteria.includes(':') ? this.byMultiParamState(criteria, ids) : this.byState(criteria, ids);
  }
  async byState(state, ids) {
    const statePerMethod = {
      new: this.byNew,
      modified: this.byModified,
      deprecated: this.byDeprecated,
      deleted: this.byDeleted,
      snappedOnMain: this.bySnappedOnMain,
      softTagged: this.bySoftTagged,
      codeModified: this.byCodeModified,
      localOnly: this.byLocalOnly
    };
    if (!statePerMethod[state]) {
      throw new Error(`state ${state} is not recognized, possible values: ${statesFilter.join(', ')}`);
    }
    return statePerMethod[state].bind(this)(ids);
  }
  async byMultiParamState(state, ids) {
    const stateSplit = state.split(':');
    if (stateSplit.length < 2) {
      throw new Error(`byMultiParamState expect the state to have at least one param after the colon, got ${state}`);
    }
    const [stateName, ...stateParams] = stateSplit;
    if (stateName === 'env') {
      return this.byEnv(stateParams[0], ids);
    }
    throw new Error(`byMultiParamState expect the state to be one of the following: ['env'], got ${stateName}`);
  }
  async byEnv(env, withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    const comps = await this.workspace.getMany(ids);
    const compsUsingEnv = comps.filter(c => {
      const envId = this.workspace.envs.getEnvId(c);
      const envIdWithoutVer = _componentId().ComponentID.getStringWithoutVersion(envId);
      return envIdWithoutVer === env;
    });
    return compsUsingEnv.map(c => c.id);
  }
  async byModified(withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    const comps = await this.workspace.getMany(ids);
    const modifiedIds = await Promise.all(comps.map(async comp => (await comp.isModified()) ? comp.id : undefined));
    return (0, _lodash().compact)(modifiedIds);
  }
  async byCodeModified(withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    const compFiles = await (0, _pMapSeries().default)(ids, id => this.workspace.getFilesModification(id));
    const modifiedIds = compFiles.filter(c => c.isModified()).map(c => c.id);
    return (0, _lodash().compact)(modifiedIds);
  }
  byLocalOnly(withinIds) {
    const ids = withinIds || this.workspace.listIds();
    return ids.filter(id => this.workspace.bitMap.getBitmapEntry(id, {
      ignoreVersion: true
    }).localOnly);
  }
  async byNew(withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    return ids.filter(id => !id.hasVersion());
  }
  async byDeprecated(withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    const comps = await this.workspace.getMany(ids);
    const results = await Promise.all(comps.map(async c => {
      const modelComponent = await this.workspace.consumer.scope.getModelComponentIfExist(c.id);
      const deprecated = await modelComponent?.isDeprecated(this.workspace.consumer.scope.objects);
      return deprecated ? c.id : null;
    }));
    return (0, _lodash().compact)(results);
  }
  async byDeleted(withinIds) {
    const ids = withinIds || (await this.workspace.listIds());
    const comps = await this.workspace.getMany(ids);
    const deletedIds = comps.filter(c => c.isDeleted()).map(c => c.id);
    return (0, _lodash().compact)(deletedIds);
  }
  byDuringMergeState() {
    const unmergedComponents = this.workspace.scope.legacyScope.objects.unmergedComponents.getComponents();
    return _componentId().ComponentIdList.fromArray(unmergedComponents.map(u => _componentId().ComponentID.fromObject(u.id)));
  }

  /**
   * list components that their head is a snap, not a tag.
   * this is relevant only when the lane is the default (main), otherwise, the head is always a snap.
   * components that are during-merge are filtered out, we don't want them during tag and don't want
   * to show them in the "snapped" section in bit-status.
   */
  async bySnappedOnMain(withinIds) {
    if (!this.workspace.isOnMain()) {
      return [];
    }
    const ids = withinIds || (await this.workspace.listIds());
    const compIds = _componentId().ComponentIdList.fromArray(ids);
    const componentsFromModel = await this.getModelComps(ids);
    const compsDuringMerge = this.byDuringMergeState();
    const comps = componentsFromModel.filter(c => compIds.hasWithoutVersion(c.toComponentId())).filter(c => !compsDuringMerge.hasWithoutVersion(c.toComponentId())).filter(c => c.isHeadSnap());
    return comps.map(c => c.toComponentIdWithHead());
  }
  bySoftTagged(withinIds) {
    const withCompIds = _componentId().ComponentIdList.fromArray(withinIds || []);
    const all = this.workspace.consumer.bitMap.components.filter(c => c.nextVersion).map(c => c.id);
    return withinIds ? all.filter(id => withCompIds.hasWithoutVersion(id)) : all;
  }
  async getModelComps(ids) {
    const comps = await Promise.all(ids.map(id => this.workspace.scope.getBitObjectModelComponent(id, false)));
    return (0, _lodash().compact)(comps);
  }
}
exports.Filter = Filter;

//# sourceMappingURL=filter.js.map