"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.fetchTerms2CategoriesCounts = fetchTerms2CategoriesCounts;
var _lodash = require("lodash");
var _mlIsPopulatedObject = require("@kbn/ml-is-populated-object");
var _get_category_query = require("../../../common/api/log_categorization/get_category_query");
var _constants = require("../../../common/constants");
var _is_request_aborted_error = require("../../lib/is_request_aborted_error");
var _get_query_with_params = require("./get_query_with_params");
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */

const isMsearchResponseItem = arg => (0, _mlIsPopulatedObject.isPopulatedObject)(arg, ['hits']);
const getTerm2CategoryCountRequest = (params, fieldValuePairs, categoryFieldName, category, from, to) => {
  var _query$bool;
  const query = (0, _get_query_with_params.getQueryWithParams)({
    params
  });
  const categoryQuery = (0, _get_category_query.getCategoryQuery)(categoryFieldName, [category]);
  if (Array.isArray((_query$bool = query.bool) === null || _query$bool === void 0 ? void 0 : _query$bool.filter)) {
    var _query$bool3, _query$bool3$filter, _query$bool4, _query$bool4$filter;
    for (const {
      fieldName,
      fieldValue
    } of fieldValuePairs) {
      var _query$bool2, _query$bool2$filter;
      (_query$bool2 = query.bool) === null || _query$bool2 === void 0 ? void 0 : (_query$bool2$filter = _query$bool2.filter) === null || _query$bool2$filter === void 0 ? void 0 : _query$bool2$filter.push({
        term: {
          [fieldName]: fieldValue
        }
      });
    }
    (_query$bool3 = query.bool) === null || _query$bool3 === void 0 ? void 0 : (_query$bool3$filter = _query$bool3.filter) === null || _query$bool3$filter === void 0 ? void 0 : _query$bool3$filter.push(categoryQuery);
    (_query$bool4 = query.bool) === null || _query$bool4 === void 0 ? void 0 : (_query$bool4$filter = _query$bool4.filter) === null || _query$bool4$filter === void 0 ? void 0 : _query$bool4$filter.push({
      range: {
        [params.timeFieldName]: {
          gte: from,
          lte: to,
          format: 'epoch_millis'
        }
      }
    });
  }
  return {
    query,
    size: 0,
    track_total_hits: true
  };
};
async function fetchTerms2CategoriesCounts(esClient, params, searchQuery, significantTerms, itemSets, significantCategories, from, to, logger, emitError, abortSignal) {
  const searches = [];
  const results = [];
  significantCategories.forEach(category => {
    significantTerms.forEach(term => {
      var _term$pValue, _category$pValue;
      searches.push({
        index: params.index
      });
      searches.push(getTerm2CategoryCountRequest(params, [{
        fieldName: term.fieldName,
        fieldValue: term.fieldValue
      }], category.fieldName, {
        key: `${category.key}`,
        count: category.doc_count,
        examples: []
      }, from, to));
      results.push({
        set: {
          [term.fieldName]: term.fieldValue,
          [category.fieldName]: category.fieldValue
        },
        size: 2,
        maxPValue: Math.max((_term$pValue = term.pValue) !== null && _term$pValue !== void 0 ? _term$pValue : 1, (_category$pValue = category.pValue) !== null && _category$pValue !== void 0 ? _category$pValue : 1),
        doc_count: 0,
        support: 0,
        total_doc_count: Math.max(term.total_doc_count, category.total_doc_count)
      });
    });
    itemSets.forEach(itemSet => {
      var _itemSet$maxPValue, _category$pValue2;
      searches.push({
        index: params.index
      });
      searches.push(getTerm2CategoryCountRequest(params, Object.entries(itemSet.set).map(([fieldName, fieldValue]) => ({
        fieldName,
        fieldValue
      })), category.fieldName, {
        key: `${category.key}`,
        count: category.doc_count,
        examples: []
      }, from, to));
      results.push({
        set: {
          ...itemSet.set,
          [category.fieldName]: category.fieldValue
        },
        size: Object.keys(itemSet.set).length + 1,
        maxPValue: Math.max((_itemSet$maxPValue = itemSet.maxPValue) !== null && _itemSet$maxPValue !== void 0 ? _itemSet$maxPValue : 1, (_category$pValue2 = category.pValue) !== null && _category$pValue2 !== void 0 ? _category$pValue2 : 1),
        doc_count: 0,
        support: 0,
        total_doc_count: Math.max(itemSet.total_doc_count, category.total_doc_count)
      });
    });
  });
  let mSearchresponse;
  try {
    mSearchresponse = await esClient.msearch({
      searches
    }, {
      signal: abortSignal,
      maxRetries: 0
    });
  } catch (error) {
    if (!(0, _is_request_aborted_error.isRequestAbortedError)(error)) {
      logger.error(`Failed to fetch term/category counts, got: \n${JSON.stringify(error, null, 2)}`);
      emitError(`Failed to fetch term/category counts.`);
    }
    return {
      fields: [],
      itemSets: [],
      totalDocCount: 0
    };
  }
  const mSearchResponses = mSearchresponse.responses;
  return {
    fields: (0, _lodash.uniq)(significantCategories.map(c => c.fieldName)),
    itemSets: results.map((result, i) => {
      const resp = mSearchResponses[i];
      if (isMsearchResponseItem(resp)) {
        var _value;
        result.doc_count = (_value = resp.hits.total.value) !== null && _value !== void 0 ? _value : 0;
        if (result.total_doc_count > 0) {
          // Replicates how the `frequent_item_sets` aggregation calculates
          // the support value by dividing the number of documents containing
          // the item set by the total number of documents.
          result.support = result.doc_count / result.total_doc_count;
        }
      }
      return result;
    }).filter(d => d.doc_count > 0 && d.support > _constants.LOG_RATE_ANALYSIS_SETTINGS.FREQUENT_ITEMS_SETS_MINIMUM_SUPPORT),
    totalDocCount: 0
  };
}