"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.tryToEnableTasks = exports.bulkEnableRules = void 0;
var _pMap = _interopRequireDefault(require("p-map"));
var _esQuery = require("@kbn/es-query");
var _apmUtils = require("@kbn/apm-utils");
var _server = require("@kbn/task-manager-plugin/server");
var _lib = require("../../lib");
var _audit_events = require("../common/audit_events");
var _common = require("../common");
var _common2 = require("../../../common");
var _lib2 = require("../lib");
var _get_schedule_frequency = require("../../application/rule/methods/get_schedule_frequency");
/*
 * 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 getShouldScheduleTask = async (context, scheduledTaskId) => {
  if (!scheduledTaskId) return true;
  try {
    // make sure scheduledTaskId exist
    return await (0, _apmUtils.withSpan)({
      name: 'getShouldScheduleTask',
      type: 'rules'
    }, async () => {
      const task = await context.taskManager.get(scheduledTaskId);

      // Check whether task status is unrecognized. If so, we want to delete
      // this task and create a fresh one
      if (task.status === _server.TaskStatus.Unrecognized) {
        await context.taskManager.removeIfExists(scheduledTaskId);
        return true;
      }
      return false;
    });
  } catch (err) {
    return true;
  }
};
const bulkEnableRules = async (context, options) => {
  const {
    ids,
    filter
  } = (0, _common.getAndValidateCommonBulkOptions)(options);
  const kueryNodeFilter = ids ? (0, _lib.convertRuleIdsToKueryNode)(ids) : (0, _common.buildKueryNodeFilter)(filter);
  const authorizationFilter = await (0, _lib2.getAuthorizationFilter)(context, {
    action: 'ENABLE'
  });
  const kueryNodeFilterWithAuth = authorizationFilter && kueryNodeFilter ? _esQuery.nodeBuilder.and([kueryNodeFilter, authorizationFilter]) : kueryNodeFilter;
  const {
    total
  } = await (0, _lib2.checkAuthorizationAndGetTotal)(context, {
    filter: kueryNodeFilterWithAuth,
    action: 'ENABLE'
  });
  const {
    errors,
    rules,
    accListSpecificForBulkOperation
  } = await (0, _common.retryIfBulkOperationConflicts)({
    action: 'ENABLE',
    logger: context.logger,
    bulkOperation: filterKueryNode => bulkEnableRulesWithOCC(context, {
      filter: filterKueryNode
    }),
    filter: kueryNodeFilterWithAuth
  });
  const [taskIdsToEnable] = accListSpecificForBulkOperation;
  const taskIdsFailedToBeEnabled = await tryToEnableTasks({
    taskIdsToEnable,
    logger: context.logger,
    taskManager: context.taskManager
  });
  const updatedRules = rules.map(({
    id,
    attributes,
    references
  }) => {
    return (0, _lib2.getAlertFromRaw)(context, id, attributes.alertTypeId, attributes, references, false);
  });
  return {
    errors,
    rules: updatedRules,
    total,
    taskIdsFailedToBeEnabled
  };
};
exports.bulkEnableRules = bulkEnableRules;
const bulkEnableRulesWithOCC = async (context, {
  filter
}) => {
  const additionalFilter = _esQuery.nodeBuilder.is('alert.attributes.enabled', 'false');
  const rulesFinder = await (0, _apmUtils.withSpan)({
    name: 'encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser',
    type: 'rules'
  }, async () => await context.encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser({
    filter: filter ? _esQuery.nodeBuilder.and([filter, additionalFilter]) : additionalFilter,
    type: 'alert',
    perPage: 100,
    ...(context.namespace ? {
      namespaces: [context.namespace]
    } : undefined)
  }));
  const rulesFinderRules = [];
  const rulesToEnable = [];
  const errors = [];
  const ruleNameToRuleIdMapping = {};
  const username = await context.getUserName();
  let scheduleValidationError = '';
  await (0, _apmUtils.withSpan)({
    name: 'Get rules, collect them and their attributes',
    type: 'rules'
  }, async () => {
    for await (const response of rulesFinder.find()) {
      rulesFinderRules.push(...response.saved_objects);
    }
    await rulesFinder.close();
    const updatedInterval = rulesFinderRules.filter(rule => !rule.attributes.enabled).map(rule => {
      var _rule$attributes$sche;
      return (_rule$attributes$sche = rule.attributes.schedule) === null || _rule$attributes$sche === void 0 ? void 0 : _rule$attributes$sche.interval;
    });
    const validationPayload = await (0, _get_schedule_frequency.validateScheduleLimit)({
      context,
      updatedInterval
    });
    if (validationPayload) {
      scheduleValidationError = (0, _common2.getRuleCircuitBreakerErrorMessage)({
        interval: validationPayload.interval,
        intervalAvailable: validationPayload.intervalAvailable,
        action: 'bulkEnable',
        rules: updatedInterval.length
      });
    }
    await (0, _pMap.default)(rulesFinderRules, async rule => {
      try {
        var _context$auditLogger;
        if (scheduleValidationError) {
          throw Error(scheduleValidationError);
        }
        if (rule.attributes.actions.length) {
          try {
            await context.actionsAuthorization.ensureAuthorized({
              operation: 'execute'
            });
          } catch (error) {
            throw Error(`Rule not authorized for bulk enable - ${error.message}`);
          }
        }
        if (rule.attributes.name) {
          ruleNameToRuleIdMapping[rule.id] = rule.attributes.name;
        }
        const migratedActions = await (0, _lib2.migrateLegacyActions)(context, {
          ruleId: rule.id,
          actions: rule.attributes.actions,
          references: rule.references,
          attributes: rule.attributes
        });
        const updatedAttributes = (0, _lib2.updateMeta)(context, {
          ...rule.attributes,
          ...(!rule.attributes.apiKey && (await (0, _lib2.createNewAPIKeySet)(context, {
            id: rule.attributes.alertTypeId,
            ruleName: rule.attributes.name,
            username,
            shouldUpdateApiKey: true
          }))),
          ...(migratedActions.hasLegacyActions ? {
            actions: migratedActions.resultedActions,
            throttle: undefined,
            notifyWhen: undefined
          } : {}),
          enabled: true,
          updatedBy: username,
          updatedAt: new Date().toISOString(),
          executionStatus: {
            status: 'pending',
            lastDuration: 0,
            lastExecutionDate: new Date().toISOString(),
            error: null,
            warning: null
          }
        });
        const shouldScheduleTask = await getShouldScheduleTask(context, rule.attributes.scheduledTaskId);
        let scheduledTaskId;
        if (shouldScheduleTask) {
          const scheduledTask = await (0, _lib2.scheduleTask)(context, {
            id: rule.id,
            consumer: rule.attributes.consumer,
            ruleTypeId: rule.attributes.alertTypeId,
            schedule: rule.attributes.schedule,
            throwOnConflict: false
          });
          scheduledTaskId = scheduledTask.id;
        }
        rulesToEnable.push({
          ...rule,
          attributes: {
            ...updatedAttributes,
            ...(scheduledTaskId ? {
              scheduledTaskId
            } : undefined)
          },
          ...(migratedActions.hasLegacyActions ? {
            references: migratedActions.resultedReferences
          } : {})
        });
        (_context$auditLogger = context.auditLogger) === null || _context$auditLogger === void 0 ? void 0 : _context$auditLogger.log((0, _audit_events.ruleAuditEvent)({
          action: _audit_events.RuleAuditAction.ENABLE,
          outcome: 'unknown',
          savedObject: {
            type: 'alert',
            id: rule.id
          }
        }));
      } catch (error) {
        var _rule$attributes, _context$auditLogger2;
        errors.push({
          message: error.message,
          rule: {
            id: rule.id,
            name: (_rule$attributes = rule.attributes) === null || _rule$attributes === void 0 ? void 0 : _rule$attributes.name
          }
        });
        (_context$auditLogger2 = context.auditLogger) === null || _context$auditLogger2 === void 0 ? void 0 : _context$auditLogger2.log((0, _audit_events.ruleAuditEvent)({
          action: _audit_events.RuleAuditAction.ENABLE,
          error
        }));
      }
    });
  });
  const result = await (0, _apmUtils.withSpan)({
    name: 'unsecuredSavedObjectsClient.bulkCreate',
    type: 'rules'
  }, () => context.unsecuredSavedObjectsClient.bulkCreate(rulesToEnable, {
    overwrite: true
  }));
  const rules = [];
  const taskIdsToEnable = [];
  result.saved_objects.forEach(rule => {
    if (rule.error === undefined) {
      if (rule.attributes.scheduledTaskId) {
        taskIdsToEnable.push(rule.attributes.scheduledTaskId);
      }
      rules.push(rule);
    } else {
      var _rule$error$message, _ruleNameToRuleIdMapp;
      errors.push({
        message: (_rule$error$message = rule.error.message) !== null && _rule$error$message !== void 0 ? _rule$error$message : 'n/a',
        status: rule.error.statusCode,
        rule: {
          id: rule.id,
          name: (_ruleNameToRuleIdMapp = ruleNameToRuleIdMapping[rule.id]) !== null && _ruleNameToRuleIdMapp !== void 0 ? _ruleNameToRuleIdMapp : 'n/a'
        }
      });
    }
  });
  return {
    errors,
    // TODO: delete the casting when we do versioning of bulk disable api
    rules: rules,
    accListSpecificForBulkOperation: [taskIdsToEnable]
  };
};
const tryToEnableTasks = async ({
  taskIdsToEnable,
  logger,
  taskManager
}) => {
  const taskIdsFailedToBeEnabled = [];
  if (taskIdsToEnable.length > 0) {
    try {
      var _resultFromEnablingTa;
      const resultFromEnablingTasks = await (0, _apmUtils.withSpan)({
        name: 'taskManager.bulkEnable',
        type: 'rules'
      }, async () => taskManager.bulkEnable(taskIdsToEnable));
      resultFromEnablingTasks === null || resultFromEnablingTasks === void 0 ? void 0 : (_resultFromEnablingTa = resultFromEnablingTasks.errors) === null || _resultFromEnablingTa === void 0 ? void 0 : _resultFromEnablingTa.forEach(error => {
        taskIdsFailedToBeEnabled.push(error.id);
      });
      if (resultFromEnablingTasks.tasks.length) {
        logger.debug(`Successfully enabled schedules for underlying tasks: ${resultFromEnablingTasks.tasks.map(task => task.id).join(', ')}`);
      }
      if (resultFromEnablingTasks.errors.length) {
        logger.error(`Failure to enable schedules for underlying tasks: ${resultFromEnablingTasks.errors.map(error => error.id).join(', ')}`);
      }
    } catch (error) {
      taskIdsFailedToBeEnabled.push(...taskIdsToEnable);
      logger.error(`Failure to enable schedules for underlying tasks: ${taskIdsToEnable.join(', ')}. TaskManager bulkEnable failed with Error: ${error.message}`);
    }
  }
  return taskIdsFailedToBeEnabled;
};
exports.tryToEnableTasks = tryToEnableTasks;