"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.PreflightCheckHelper = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _coreElasticsearchServerInternal = require("@kbn/core-elasticsearch-server-internal");
var _coreSavedObjectsUtilsServer = require("@kbn/core-saved-objects-utils-server");
var _coreSavedObjectsServer = require("@kbn/core-saved-objects-server");
var _utils = require("../utils");
var _preflight_check_for_create = require("../internals/preflight_check_for_create");
/*
 * 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 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

class PreflightCheckHelper {
  constructor({
    registry,
    serializer,
    client,
    getIndexForType,
    createPointInTimeFinder
  }) {
    (0, _defineProperty2.default)(this, "registry", void 0);
    (0, _defineProperty2.default)(this, "serializer", void 0);
    (0, _defineProperty2.default)(this, "client", void 0);
    (0, _defineProperty2.default)(this, "getIndexForType", void 0);
    (0, _defineProperty2.default)(this, "createPointInTimeFinder", void 0);
    this.registry = registry;
    this.serializer = serializer;
    this.client = client;
    this.getIndexForType = getIndexForType;
    this.createPointInTimeFinder = createPointInTimeFinder;
  }
  async preflightCheckForCreate(objects) {
    return await (0, _preflight_check_for_create.preflightCheckForCreate)({
      objects,
      registry: this.registry,
      client: this.client,
      serializer: this.serializer,
      getIndexForType: this.getIndexForType.bind(this),
      createPointInTimeFinder: this.createPointInTimeFinder.bind(this)
    });
  }

  /**
   * Fetch multi-namespace saved objects
   * @returns MgetResponse
   * @notes multi-namespace objects shared to more than one space require special handling. We fetch these docs to retrieve their namespaces.
   * @internal
   */
  async preflightCheckForBulkDelete(params) {
    const {
      expectedBulkGetResults,
      namespace
    } = params;
    const bulkGetMultiNamespaceDocs = expectedBulkGetResults.filter(_utils.isRight).filter(({
      value
    }) => value.esRequestIndex !== undefined).map(({
      value: {
        type,
        id
      }
    }) => ({
      _id: this.serializer.generateRawId(namespace, type, id),
      _index: this.getIndexForType(type),
      _source: ['type', 'namespaces']
    }));
    const bulkGetMultiNamespaceDocsResponse = bulkGetMultiNamespaceDocs.length ? await this.client.mget({
      body: {
        docs: bulkGetMultiNamespaceDocs
      }
    }, {
      ignore: [404],
      meta: true
    }) : undefined;
    // fail fast if we can't verify a 404 response is from Elasticsearch
    if (bulkGetMultiNamespaceDocsResponse && (0, _coreElasticsearchServerInternal.isNotFoundFromUnsupportedServer)({
      statusCode: bulkGetMultiNamespaceDocsResponse.statusCode,
      headers: bulkGetMultiNamespaceDocsResponse.headers
    })) {
      throw _coreSavedObjectsServer.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError();
    }
    return bulkGetMultiNamespaceDocsResponse;
  }

  /**
   * Pre-flight check to ensure that a multi-namespace object exists in the current namespace.
   */
  async preflightCheckNamespaces({
    type,
    id,
    namespace,
    initialNamespaces
  }) {
    if (!this.registry.isMultiNamespace(type)) {
      throw new Error(`Cannot make preflight get request for non-multi-namespace type '${type}'.`);
    }
    const {
      body,
      statusCode,
      headers
    } = await this.client.get({
      id: this.serializer.generateRawId(undefined, type, id),
      index: this.getIndexForType(type)
    }, {
      ignore: [404],
      meta: true
    });
    const namespaces = initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : [_coreSavedObjectsUtilsServer.SavedObjectsUtils.namespaceIdToString(namespace)];
    const indexFound = statusCode !== 404;
    if (indexFound && (0, _utils.isFoundGetResponse)(body)) {
      if (!(0, _utils.rawDocExistsInNamespaces)(this.registry, body, namespaces)) {
        return {
          checkResult: 'found_outside_namespace'
        };
      }
      return {
        checkResult: 'found_in_namespace',
        savedObjectNamespaces: initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : (0, _utils.getSavedObjectNamespaces)(namespace, body),
        rawDocSource: body
      };
    } else if ((0, _coreElasticsearchServerInternal.isNotFoundFromUnsupportedServer)({
      statusCode,
      headers
    })) {
      // checking if the 404 is from Elasticsearch
      throw _coreSavedObjectsServer.SavedObjectsErrorHelpers.createGenericNotFoundError(type, id);
    }
    return {
      checkResult: 'not_found',
      savedObjectNamespaces: initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : (0, _utils.getSavedObjectNamespaces)(namespace)
    };
  }

  /**
   * Pre-flight check fetching the document regardless of its namespace type for update.
   */
  async preflightGetDocForUpdate({
    type,
    id,
    namespace
  }) {
    const {
      statusCode,
      body,
      headers
    } = await this.client.get({
      id: this.serializer.generateRawId(namespace, type, id),
      index: this.getIndexForType(type)
    }, {
      ignore: [404],
      meta: true
    });

    // checking if the 404 is from Elasticsearch
    if ((0, _coreElasticsearchServerInternal.isNotFoundFromUnsupportedServer)({
      statusCode,
      headers
    })) {
      throw _coreSavedObjectsServer.SavedObjectsErrorHelpers.createGenericNotFoundEsUnavailableError(type, id);
    }
    const indexFound = statusCode !== 404;
    if (indexFound && (0, _utils.isFoundGetResponse)(body)) {
      return {
        checkDocFound: 'found',
        rawDocSource: body
      };
    }
    return {
      checkDocFound: 'not_found'
    };
  }

  /**
   * Pre-flight check to ensure that a multi-namespace object exists in the current namespace for update API.
   */
  preflightCheckNamespacesForUpdate({
    type,
    namespace,
    initialNamespaces,
    preflightDocResult
  }) {
    const {
      checkDocFound,
      rawDocSource
    } = preflightDocResult;
    if (!this.registry.isMultiNamespace(type)) {
      return {
        checkSkipped: true
      };
    }
    const namespaces = initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : [_coreSavedObjectsUtilsServer.SavedObjectsUtils.namespaceIdToString(namespace)];
    if (checkDocFound === 'found' && rawDocSource !== undefined) {
      if (!(0, _utils.rawDocExistsInNamespaces)(this.registry, rawDocSource, namespaces)) {
        return {
          checkResult: 'found_outside_namespace',
          checkSkipped: false
        };
      }
      return {
        checkResult: 'found_in_namespace',
        savedObjectNamespaces: initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : (0, _utils.getSavedObjectNamespaces)(namespace, rawDocSource),
        rawDocSource,
        checkSkipped: false
      };
    }
    return {
      checkResult: 'not_found',
      savedObjectNamespaces: initialNamespaces !== null && initialNamespaces !== void 0 ? initialNamespaces : (0, _utils.getSavedObjectNamespaces)(namespace),
      checkSkipped: false
    };
  }

  /**
   * Pre-flight check to ensure that an upsert which would create a new object does not result in an alias conflict.
   *
   * If an upsert would result in the creation of a new object, we need to check for alias conflicts too.
   * This takes an extra round trip to Elasticsearch, but this won't happen often.
   */
  async preflightCheckForUpsertAliasConflict(type, id, namespace) {
    const namespaceString = _coreSavedObjectsUtilsServer.SavedObjectsUtils.namespaceIdToString(namespace);
    const [{
      error
    }] = await (0, _preflight_check_for_create.preflightCheckForCreate)({
      registry: this.registry,
      client: this.client,
      serializer: this.serializer,
      getIndexForType: this.getIndexForType.bind(this),
      createPointInTimeFinder: this.createPointInTimeFinder.bind(this),
      objects: [{
        type,
        id,
        namespaces: [namespaceString]
      }]
    });
    if ((error === null || error === void 0 ? void 0 : error.type) === 'aliasConflict') {
      throw _coreSavedObjectsServer.SavedObjectsErrorHelpers.createConflictError(type, id);
    }
    // any other error from this check does not matter
  }
}

/**
 * @internal
 */

/**
 * @internal
 */

/**
 * @internal
 */

/**
 * @internal
 */

/**
 * @internal
 */

/**
 * @internal
 */
exports.PreflightCheckHelper = PreflightCheckHelper;