"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.registerTransactionDurationRuleType = registerTransactionDurationRuleType;
exports.transactionDurationActionVariables = void 0;
var _server = require("@kbn/core/server");
var _common = require("@kbn/observability-plugin/common");
var _server2 = require("@kbn/observability-plugin/server");
var _ruleDataUtils = require("@kbn/rule-data-utils");
var _server3 = require("@kbn/rule-registry-plugin/server");
var _common2 = require("@kbn/spaces-plugin/common");
var _get_groupby_terms = require("../utils/get_groupby_terms");
var _aggregated_transactions = require("../../../../../common/aggregated_transactions");
var _environment_filter_values = require("../../../../../common/environment_filter_values");
var _apm = require("../../../../../common/es_fields/apm");
var _apm_rule_types = require("../../../../../common/rules/apm_rule_types");
var _schema = require("../../../../../common/rules/schema");
var _environment_query = require("../../../../../common/utils/environment_query");
var _formatters = require("../../../../../common/utils/formatters");
var _transactions = require("../../../../lib/helpers/transactions");
var _action_variables = require("../../action_variables");
var _alerting_es_client = require("../../alerting_es_client");
var _register_apm_rule_types = require("../../register_apm_rule_types");
var _get_service_group_fields = require("../get_service_group_fields");
var _average_or_percentile_agg = require("./average_or_percentile_agg");
var _get_groupby_action_variables = require("../utils/get_groupby_action_variables");
var _get_all_groupby_fields = require("../../../../../common/rules/get_all_groupby_fields");
/*
 * 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 ruleTypeConfig = _apm_rule_types.RULE_TYPES_CONFIG[_apm_rule_types.ApmRuleType.TransactionDuration];
const transactionDurationActionVariables = [_action_variables.apmActionVariables.alertDetailsUrl, _action_variables.apmActionVariables.environment, _action_variables.apmActionVariables.interval, _action_variables.apmActionVariables.reason, _action_variables.apmActionVariables.serviceName, _action_variables.apmActionVariables.threshold, _action_variables.apmActionVariables.transactionName, _action_variables.apmActionVariables.transactionType, _action_variables.apmActionVariables.triggerValue, _action_variables.apmActionVariables.viewInAppUrl];
exports.transactionDurationActionVariables = transactionDurationActionVariables;
function registerTransactionDurationRuleType({
  alerting,
  ruleDataClient,
  getApmIndices,
  apmConfig,
  logger,
  basePath
}) {
  const createLifecycleRuleType = (0, _server3.createLifecycleRuleTypeFactory)({
    ruleDataClient,
    logger
  });
  const ruleType = createLifecycleRuleType({
    id: _apm_rule_types.ApmRuleType.TransactionDuration,
    name: ruleTypeConfig.name,
    actionGroups: ruleTypeConfig.actionGroups,
    defaultActionGroupId: ruleTypeConfig.defaultActionGroupId,
    validate: {
      params: _schema.transactionDurationParamsSchema
    },
    actionVariables: {
      context: transactionDurationActionVariables
    },
    category: _server.DEFAULT_APP_CATEGORIES.observability.id,
    producer: _apm_rule_types.APM_SERVER_FEATURE_ID,
    minimumLicenseRequired: 'basic',
    isExportable: true,
    executor: async ({
      params: ruleParams,
      services,
      spaceId
    }) => {
      var _ruleParams$searchCon, _ruleParams$searchCon2, _ruleParams$searchCon3, _ruleParams$searchCon4;
      const allGroupByFields = (0, _get_all_groupby_fields.getAllGroupByFields)(_apm_rule_types.ApmRuleType.TransactionDuration, ruleParams.groupBy);
      const {
        getAlertUuid,
        savedObjectsClient,
        scopedClusterClient
      } = services;
      const indices = await getApmIndices(savedObjectsClient);

      // only query transaction events when set to 'never',
      // to prevent (likely) unnecessary blocking request
      // in rule execution
      const searchAggregatedTransactions = apmConfig.searchAggregatedTransactions !== _aggregated_transactions.SearchAggregatedTransactionSetting.never;
      const index = searchAggregatedTransactions ? indices.metric : indices.transaction;
      const field = (0, _transactions.getDurationFieldForTransactions)(searchAggregatedTransactions);
      const termFilterQuery = !((_ruleParams$searchCon = ruleParams.searchConfiguration) !== null && _ruleParams$searchCon !== void 0 && (_ruleParams$searchCon2 = _ruleParams$searchCon.query) !== null && _ruleParams$searchCon2 !== void 0 && _ruleParams$searchCon2.query) ? [...(0, _server2.termQuery)(_apm.SERVICE_NAME, ruleParams.serviceName, {
        queryEmptyString: false
      }), ...(0, _server2.termQuery)(_apm.TRANSACTION_TYPE, ruleParams.transactionType, {
        queryEmptyString: false
      }), ...(0, _server2.termQuery)(_apm.TRANSACTION_NAME, ruleParams.transactionName, {
        queryEmptyString: false
      }), ...(0, _environment_query.environmentQuery)(ruleParams.environment)] : [];
      const searchParams = {
        index,
        body: {
          track_total_hits: false,
          size: 0,
          query: {
            bool: {
              filter: [{
                range: {
                  '@timestamp': {
                    gte: `now-${ruleParams.windowSize}${ruleParams.windowUnit}`
                  }
                }
              }, ...(0, _transactions.getBackwardCompatibleDocumentTypeFilter)(searchAggregatedTransactions), ...termFilterQuery, ...(0, _server2.getParsedFilterQuery)((_ruleParams$searchCon3 = ruleParams.searchConfiguration) === null || _ruleParams$searchCon3 === void 0 ? void 0 : (_ruleParams$searchCon4 = _ruleParams$searchCon3.query) === null || _ruleParams$searchCon4 === void 0 ? void 0 : _ruleParams$searchCon4.query)]
            }
          },
          aggs: {
            series: {
              multi_terms: {
                terms: [...(0, _get_groupby_terms.getGroupByTerms)(allGroupByFields)],
                size: 1000,
                ...(0, _average_or_percentile_agg.getMultiTermsSortOrder)(ruleParams.aggregationType)
              },
              aggs: {
                ...(0, _average_or_percentile_agg.averageOrPercentileAgg)({
                  aggregationType: ruleParams.aggregationType,
                  transactionDurationField: field
                }),
                ...(0, _get_service_group_fields.getServiceGroupFieldsAgg)()
              }
            }
          }
        }
      };
      const response = await (0, _alerting_es_client.alertingEsClient)({
        scopedClusterClient,
        params: searchParams
      });
      if (!response.aggregations) {
        return {
          state: {}
        };
      }

      // Converts threshold to microseconds because this is the unit used on transactionDuration
      const thresholdMicroseconds = ruleParams.threshold * 1000;
      const triggeredBuckets = [];
      for (const bucket of response.aggregations.series.buckets) {
        const groupByFields = bucket.key.reduce((obj, bucketKey, bucketIndex) => {
          obj[allGroupByFields[bucketIndex]] = bucketKey;
          return obj;
        }, {});
        const bucketKey = bucket.key;
        const transactionDuration = 'avgLatency' in bucket // only true if ruleParams.aggregationType === 'avg'
        ? bucket.avgLatency.value : bucket.pctLatency.values[0].value;
        if (transactionDuration !== null && transactionDuration > thresholdMicroseconds) {
          triggeredBuckets.push({
            sourceFields: (0, _get_service_group_fields.getServiceGroupFields)(bucket),
            transactionDuration,
            groupByFields,
            bucketKey
          });
        }
      }
      for (const {
        transactionDuration,
        sourceFields,
        groupByFields,
        bucketKey
      } of triggeredBuckets) {
        var _getEnvironmentEsFiel;
        const durationFormatter = (0, _formatters.getDurationFormatter)(transactionDuration);
        const transactionDurationFormatted = durationFormatter(transactionDuration).formatted;
        const reason = (0, _apm_rule_types.formatTransactionDurationReason)({
          aggregationType: String(ruleParams.aggregationType),
          asDuration: _common.asDuration,
          measured: transactionDuration,
          threshold: thresholdMicroseconds,
          windowSize: ruleParams.windowSize,
          windowUnit: ruleParams.windowUnit,
          groupByFields
        });
        const alertId = bucketKey.join('_');
        const alert = services.alertWithLifecycle({
          id: alertId,
          fields: {
            [_apm.TRANSACTION_NAME]: ruleParams.transactionName,
            [_apm.PROCESSOR_EVENT]: _common.ProcessorEvent.transaction,
            [_ruleDataUtils.ALERT_EVALUATION_VALUE]: transactionDuration,
            [_ruleDataUtils.ALERT_EVALUATION_THRESHOLD]: thresholdMicroseconds,
            [_ruleDataUtils.ALERT_REASON]: reason,
            ...sourceFields,
            ...groupByFields
          }
        });
        const alertUuid = getAlertUuid(alertId);
        const alertDetailsUrl = (0, _common.getAlertDetailsUrl)(basePath, spaceId, alertUuid);
        const viewInAppUrl = (0, _common2.addSpaceIdToPath)(basePath.publicBaseUrl, spaceId, (0, _formatters.getAlertUrlTransaction)(groupByFields[_apm.SERVICE_NAME], (_getEnvironmentEsFiel = (0, _environment_filter_values.getEnvironmentEsField)(groupByFields[_apm.SERVICE_ENVIRONMENT])) === null || _getEnvironmentEsFiel === void 0 ? void 0 : _getEnvironmentEsFiel[_apm.SERVICE_ENVIRONMENT], groupByFields[_apm.TRANSACTION_TYPE]));
        const groupByActionVariables = (0, _get_groupby_action_variables.getGroupByActionVariables)(groupByFields);
        alert.scheduleActions(ruleTypeConfig.defaultActionGroupId, {
          alertDetailsUrl,
          interval: (0, _common.formatDurationFromTimeUnitChar)(ruleParams.windowSize, ruleParams.windowUnit),
          reason,
          // When group by doesn't include transaction.name, the context.transaction.name action variable will contain value of the Transaction Name filter
          transactionName: ruleParams.transactionName,
          threshold: ruleParams.threshold,
          triggerValue: transactionDurationFormatted,
          viewInAppUrl,
          ...groupByActionVariables
        });
      }
      return {
        state: {}
      };
    },
    alerts: _register_apm_rule_types.ApmRuleTypeAlertDefinition,
    getViewInAppRelativeUrl: ({
      rule
    }) => _common.observabilityPaths.ruleDetails(rule.id)
  });
  alerting.registerType(ruleType);
}