"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.SearchService = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _rxjs = require("rxjs");
var _operators = require("rxjs/operators");
var _lodash = require("lodash");
var _moment = require("moment");
var _i18n = require("@kbn/i18n");
var _errors = require("../../common/errors");
var _operators2 = require("../../common/operators");
var _constants = require("../../common/constants");
var _process_result = require("../../common/process_result");
var _utils = require("./utils");
var _fetch_server_results = require("./fetch_server_results");
var _fetch_server_searchable_types = require("./fetch_server_searchable_types");
/*
 * 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.
 */

/** @public */

/** @public */

const mapToUndefined = () => undefined;

/** @internal */
class SearchService {
  constructor() {
    (0, _defineProperty2.default)(this, "providers", new Map());
    (0, _defineProperty2.default)(this, "config", void 0);
    (0, _defineProperty2.default)(this, "http", void 0);
    (0, _defineProperty2.default)(this, "maxProviderResults", _constants.defaultMaxProviderResults);
    (0, _defineProperty2.default)(this, "licenseChecker", void 0);
    (0, _defineProperty2.default)(this, "serverTypes", void 0);
  }
  setup({
    config,
    maxProviderResults = _constants.defaultMaxProviderResults
  }) {
    this.config = config;
    this.maxProviderResults = maxProviderResults;
    return {
      registerResultProvider: provider => {
        if (this.providers.has(provider.id)) {
          throw new Error(`trying to register duplicate provider: ${provider.id}`);
        }
        this.providers.set(provider.id, provider);
      }
    };
  }
  start({
    http,
    licenseChecker
  }) {
    this.http = http;
    this.licenseChecker = licenseChecker;
    return {
      find: (params, options) => this.performFind(params, options),
      getSearchableTypes: () => this.getSearchableTypes()
    };
  }
  async getSearchableTypes() {
    const providerTypes = (await Promise.all([...this.providers.values()].map(provider => provider.getSearchableTypes()))).flat();

    // only need to fetch from server once
    if (!this.serverTypes) {
      this.serverTypes = await (0, _fetch_server_searchable_types.fetchServerSearchableTypes)(this.http);
    }
    return (0, _lodash.uniq)([...providerTypes, ...this.serverTypes]);
  }
  performFind(params, options) {
    var _options$preference;
    const licenseState = this.licenseChecker.getState();
    if (!licenseState.valid) {
      return (0, _rxjs.throwError)(_errors.GlobalSearchFindError.invalidLicense(_i18n.i18n.translate('xpack.globalSearch.find.invalidLicenseError', {
        defaultMessage: `GlobalSearch API is disabled because of invalid license state: {errorMessage}`,
        values: {
          errorMessage: licenseState.message
        }
      })));
    }
    const timeout = (0, _moment.duration)(this.config.search_timeout).asMilliseconds();
    const timeout$ = (0, _rxjs.timer)(timeout).pipe((0, _operators.map)(mapToUndefined));
    const aborted$ = options.aborted$ ? (0, _rxjs.merge)(options.aborted$, timeout$) : timeout$;
    const preference = (_options$preference = options.preference) !== null && _options$preference !== void 0 ? _options$preference : (0, _utils.getDefaultPreference)();
    const providerOptions = {
      ...options,
      preference,
      maxResults: this.maxProviderResults,
      aborted$
    };
    const processResult = result => (0, _process_result.processProviderResult)(result, this.http.basePath);
    const serverResults$ = (0, _fetch_server_results.fetchServerResults)(this.http, params, {
      preference,
      aborted$
    }).pipe((0, _operators.catchError)(() => _rxjs.EMPTY));
    const providersResults$ = [...this.providers.values()].map(provider => provider.find(params, providerOptions).pipe((0, _operators.catchError)(() => _rxjs.EMPTY), (0, _operators2.takeInArray)(this.maxProviderResults), (0, _operators.takeUntil)(aborted$), (0, _operators.map)(results => results.map(r => processResult(r)))));
    return (0, _rxjs.merge)(...providersResults$, serverResults$).pipe((0, _operators.map)(results => ({
      results
    })));
  }
}
exports.SearchService = SearchService;