"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getListHandler = void 0;
var _lodash = require("lodash");
var _types = require("../../../common/types");
var _get = require("../../services/epm/packages/get");
var _errors = require("../../errors");
var _data_streams = require("../../services/data_streams");
var _get_data_streams_query_metadata = require("./get_data_streams_query_metadata");
/*
 * 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 MANAGED_BY = 'fleet';
const LEGACY_MANAGED_BY = 'ingest-manager';
const getListHandler = async (context, request, response) => {
  // Query datastreams as the current user as the Kibana internal user may not have all the required permission
  const {
    savedObjects,
    elasticsearch
  } = await context.core;
  const esClient = elasticsearch.client.asCurrentUser;
  const body = {
    data_streams: []
  };
  try {
    // Get matching data streams, their stats, and package SOs
    const [dataStreamsInfo, dataStreamStats, packageSavedObjects] = await Promise.all([_data_streams.dataStreamService.getAllFleetDataStreams(esClient), _data_streams.dataStreamService.getAllFleetDataStreamsStats(esClient), (0, _get.getPackageSavedObjects)(savedObjects.client)]);

    // managed_by property 'ingest-manager' added to allow for legacy data streams to be displayed
    // See https://github.com/elastic/elastic-agent/issues/654

    const filteredDataStreamsInfo = dataStreamsInfo.filter(ds => {
      var _ds$_meta, _ds$_meta2;
      return (ds === null || ds === void 0 ? void 0 : (_ds$_meta = ds._meta) === null || _ds$_meta === void 0 ? void 0 : _ds$_meta.managed_by) === MANAGED_BY || (ds === null || ds === void 0 ? void 0 : (_ds$_meta2 = ds._meta) === null || _ds$_meta2 === void 0 ? void 0 : _ds$_meta2.managed_by) === LEGACY_MANAGED_BY;
    });
    const dataStreamsInfoByName = (0, _lodash.keyBy)(filteredDataStreamsInfo, 'name');
    const filteredDataStreamsStats = dataStreamStats.filter(dss => !!dataStreamsInfoByName[dss.data_stream]);
    const dataStreamsStatsByName = (0, _lodash.keyBy)(filteredDataStreamsStats, 'data_stream');

    // Combine data stream info
    const dataStreams = (0, _lodash.merge)(dataStreamsInfoByName, dataStreamsStatsByName);
    const dataStreamNames = (0, _lodash.keys)(dataStreams);

    // Map package SOs
    const packageSavedObjectsByName = (0, _lodash.keyBy)(packageSavedObjects.saved_objects, 'id');
    const packageMetadata = {};

    // Get dashboard information for all packages
    const dashboardIdsByPackageName = packageSavedObjects.saved_objects.reduce((allDashboards, pkgSavedObject) => {
      var _pkgSavedObject$attri;
      const dashboards = [];
      (((_pkgSavedObject$attri = pkgSavedObject.attributes) === null || _pkgSavedObject$attri === void 0 ? void 0 : _pkgSavedObject$attri.installed_kibana) || []).forEach(o => {
        if (o.type === _types.KibanaSavedObjectType.dashboard) {
          dashboards.push(o.id);
        }
      });
      allDashboards[pkgSavedObject.id] = dashboards;
      return allDashboards;
    }, {});
    const allDashboardSavedObjectsResponse = await savedObjects.client.bulkGet(Object.values(dashboardIdsByPackageName).flatMap(dashboardIds => dashboardIds.map(id => ({
      id,
      type: _types.KibanaSavedObjectType.dashboard,
      fields: ['title']
    }))));
    // Ignore dashboards not found
    const allDashboardSavedObjects = allDashboardSavedObjectsResponse.saved_objects.filter(so => {
      if (so.error) {
        if (so.error.statusCode === 404) {
          return false;
        }
        throw so.error;
      }
      return true;
    });
    const allDashboardSavedObjectsById = (0, _lodash.keyBy)(allDashboardSavedObjects, dashboardSavedObject => dashboardSavedObject.id);

    // Query additional information for each data stream
    const dataStreamPromises = dataStreamNames.map(async dataStreamName => {
      var _dataStream$_meta, _dataStream$_meta$pac;
      const dataStream = dataStreams[dataStreamName];
      const dataStreamResponse = {
        index: dataStreamName,
        dataset: '',
        namespace: '',
        type: '',
        package: ((_dataStream$_meta = dataStream._meta) === null || _dataStream$_meta === void 0 ? void 0 : (_dataStream$_meta$pac = _dataStream$_meta.package) === null || _dataStream$_meta$pac === void 0 ? void 0 : _dataStream$_meta$pac.name) || '',
        package_version: '',
        last_activity_ms: dataStream.maximum_timestamp,
        // overridden below if maxIngestedTimestamp agg returns a result
        size_in_bytes: dataStream.store_size_bytes,
        // `store_size` should be available from ES due to ?human=true flag
        // but fallback to bytes just in case
        size_in_bytes_formatted: dataStream.store_size || `${dataStream.store_size_bytes}b`,
        dashboards: [],
        serviceDetails: null
      };
      const {
        maxIngested,
        namespace,
        dataset,
        type,
        serviceNames,
        environments
      } = await (0, _get_data_streams_query_metadata.getDataStreamsQueryMetadata)({
        dataStreamName: dataStream.name,
        esClient
      });

      // some integrations e.g custom logs don't have event.ingested
      if (maxIngested) {
        dataStreamResponse.last_activity_ms = maxIngested;
      }
      if ((serviceNames === null || serviceNames === void 0 ? void 0 : serviceNames.length) === 1) {
        const serviceDetails = {
          serviceName: serviceNames[0],
          environment: (environments === null || environments === void 0 ? void 0 : environments.length) === 1 ? environments[0] : 'ENVIRONMENT_ALL'
        };
        dataStreamResponse.serviceDetails = serviceDetails;
      }
      dataStreamResponse.dataset = dataset;
      dataStreamResponse.namespace = namespace;
      dataStreamResponse.type = type;

      // Find package saved object
      const pkgName = dataStreamResponse.package;
      const pkgSavedObject = pkgName ? packageSavedObjectsByName[pkgName] : null;
      if (pkgSavedObject) {
        // if
        // - the data stream is associated with a package
        // - and the package has been installed through EPM
        // - and we didn't pick the metadata in an earlier iteration of this map()
        if (!packageMetadata[pkgName]) {
          var _pkgSavedObject$attri2;
          // then pick the dashboards from the package saved object
          const packageDashboardIds = dashboardIdsByPackageName[pkgName] || [];
          const packageDashboards = packageDashboardIds.reduce((dashboards, dashboardId) => {
            const dashboard = allDashboardSavedObjectsById[dashboardId];
            if (dashboard) {
              dashboards.push({
                id: dashboard.id,
                title: dashboard.attributes.title || dashboard.id
              });
            }
            return dashboards;
          }, []);
          packageMetadata[pkgName] = {
            version: ((_pkgSavedObject$attri2 = pkgSavedObject.attributes) === null || _pkgSavedObject$attri2 === void 0 ? void 0 : _pkgSavedObject$attri2.version) || '',
            dashboards: packageDashboards
          };
        }

        // Set values from package information
        dataStreamResponse.package = pkgName;
        dataStreamResponse.package_version = packageMetadata[pkgName].version;
        dataStreamResponse.dashboards = packageMetadata[pkgName].dashboards;
      }
      return dataStreamResponse;
    });

    // Return final data streams objects sorted by last activity, descending
    // After filtering out data streams that are missing dataset/namespace/type/package fields
    body.data_streams = (await Promise.all(dataStreamPromises)).filter(({
      dataset,
      namespace,
      type
    }) => dataset && namespace && type).sort((a, b) => b.last_activity_ms - a.last_activity_ms);
    return response.ok({
      body
    });
  } catch (error) {
    return (0, _errors.defaultFleetErrorHandler)({
      error,
      response
    });
  }
};
exports.getListHandler = getListHandler;