"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.LensAttributes = void 0;
exports.buildNumberColumn = buildNumberColumn;
exports.getLayerReferenceName = getLayerReferenceName;
exports.getPercentileParam = getPercentileParam;
exports.parseCustomFieldName = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _i18n = require("@kbn/i18n");
var _lodash = require("lodash");
var _esQuery = require("@kbn/es-query");
var _constants = require("@kbn/visualizations-plugin/common/constants");
var _stringify_kueries = require("../utils/stringify_kueries");
var _constants2 = require("./constants");
var _date_range_picker = require("../components/date_range_picker");
var _overall_column = require("./lens_columns/overall_column");
/*
 * 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.
 */

function getLayerReferenceName(layerId) {
  return `indexpattern-datasource-layer-${layerId}`;
}
function buildNumberColumn(sourceField) {
  return {
    sourceField,
    dataType: 'number',
    isBucketed: false,
    scale: 'ratio'
  };
}
function getPercentileParam(operationType) {
  return {
    percentile: Number(operationType.split('th')[0])
  };
}
const parseCustomFieldName = (seriesConfig, selectedMetricField) => {
  var _seriesConfig$metricO;
  const metricOptions = (_seriesConfig$metricO = seriesConfig.metricOptions) !== null && _seriesConfig$metricO !== void 0 ? _seriesConfig$metricO : [];
  if (selectedMetricField) {
    if (metricOptions) {
      var _currField$field;
      const currField = metricOptions.find(opt => {
        if ('items' in opt) {
          return opt.id === selectedMetricField;
        } else {
          return opt.field === selectedMetricField || opt.id === selectedMetricField;
        }
      });
      if (currField && 'items' in currField) {
        const currFieldItem = currField.items.find(item => item.id === selectedMetricField || item.field === selectedMetricField);
        if (currFieldItem) {
          return {
            ...(currFieldItem !== null && currFieldItem !== void 0 ? currFieldItem : {}),
            fieldName: selectedMetricField,
            columnLabel: currFieldItem === null || currFieldItem === void 0 ? void 0 : currFieldItem.label,
            columnField: currFieldItem === null || currFieldItem === void 0 ? void 0 : currFieldItem.field
          };
        }
        return currField.items;
      }
      return {
        ...(currField !== null && currField !== void 0 ? currField : {}),
        fieldName: (_currField$field = currField === null || currField === void 0 ? void 0 : currField.field) !== null && _currField$field !== void 0 ? _currField$field : selectedMetricField,
        columnLabel: currField === null || currField === void 0 ? void 0 : currField.label,
        columnField: currField === null || currField === void 0 ? void 0 : currField.field
      };
    }
  }
  return {
    fieldName: selectedMetricField
  };
};
exports.parseCustomFieldName = parseCustomFieldName;
class LensAttributes {
  constructor(layerConfigs, reportType, lensFormulaHelper) {
    (0, _defineProperty2.default)(this, "layers", void 0);
    (0, _defineProperty2.default)(this, "visualization", void 0);
    (0, _defineProperty2.default)(this, "layerConfigs", []);
    (0, _defineProperty2.default)(this, "isMultiSeries", void 0);
    (0, _defineProperty2.default)(this, "seriesReferenceLines", void 0);
    (0, _defineProperty2.default)(this, "globalFilter", void 0);
    (0, _defineProperty2.default)(this, "reportType", void 0);
    (0, _defineProperty2.default)(this, "lensFormulaHelper", void 0);
    this.layers = {};
    this.seriesReferenceLines = {};
    this.reportType = reportType;
    this.lensFormulaHelper = lensFormulaHelper;
    this.isMultiSeries = layerConfigs.length > 1;
    layerConfigs.forEach(({
      seriesConfig,
      operationType
    }) => {
      if (operationType && reportType !== _constants2.ReportTypes.SINGLE_METRIC) {
        seriesConfig.yAxisColumns.forEach(yAxisColumn => {
          if (typeof yAxisColumn.operationType !== undefined) {
            yAxisColumn.operationType = operationType;
          }
        });
      }
    });
    this.layerConfigs = layerConfigs;
    this.globalFilter = this.getGlobalFilter(this.isMultiSeries);
    if (reportType === _constants2.ReportTypes.SINGLE_METRIC) {
      return;
    }
    this.layers = this.getLayers();
    this.visualization = this.getXyState();
  }
  getGlobalFilter(isMultiSeries) {
    if (isMultiSeries) {
      return undefined;
    }
    const defaultLayerFilter = this.layerConfigs[0].seriesConfig.query ? ` and ${this.layerConfigs[0].seriesConfig.query.query}` : '';
    return {
      query: `${this.getLayerFilters(this.layerConfigs[0], this.layerConfigs.length)}${defaultLayerFilter}`,
      language: 'kuery'
    };
  }
  getBreakdownColumn({
    sourceField,
    layerId,
    layerConfig,
    alphabeticOrder,
    size = 10
  }) {
    var _seriesConfig$labels, _metricOptions$find;
    const {
      dataView,
      seriesConfig,
      selectedMetricField
    } = layerConfig;
    const fieldMeta = dataView.getFieldByName(sourceField);
    const {
      metricOptions
    } = seriesConfig;
    const {
      sourceField: yAxisSourceField
    } = seriesConfig.yAxisColumns[0];
    const labels = (_seriesConfig$labels = seriesConfig.labels) !== null && _seriesConfig$labels !== void 0 ? _seriesConfig$labels : {};
    const isFormulaColumn = Boolean(metricOptions && ((_metricOptions$find = metricOptions.find(option => option.id === selectedMetricField)) === null || _metricOptions$find === void 0 ? void 0 : _metricOptions$find.formula)) || yAxisSourceField === _constants2.RECORDS_PERCENTAGE_FIELD;
    let orderBy = {
      type: 'column',
      columnId: `y-axis-column-${layerId}-0`
    };
    if (isFormulaColumn) {
      orderBy = {
        type: 'custom'
      };
    } else if (alphabeticOrder) {
      orderBy = {
        type: 'alphabetical',
        fallback: true
      };
    }
    return {
      sourceField,
      label: labels[sourceField],
      dataType: fieldMeta === null || fieldMeta === void 0 ? void 0 : fieldMeta.type,
      operationType: 'terms',
      scale: 'ordinal',
      isBucketed: true,
      params: {
        orderBy,
        size,
        orderDirection: 'desc',
        otherBucket: true,
        missingBucket: false,
        ...(isFormulaColumn ? {
          orderAgg: {
            label: 'Count of records',
            dataType: 'number',
            operationType: 'count',
            isBucketed: false,
            scale: 'ratio',
            sourceField: '___records___'
          }
        } : {})
      }
    };
  }
  getNumberRangeColumn(sourceField, seriesConfig, label) {
    var _seriesConfig$labels$;
    return {
      sourceField,
      label: (_seriesConfig$labels$ = seriesConfig.labels[sourceField]) !== null && _seriesConfig$labels$ !== void 0 ? _seriesConfig$labels$ : label,
      dataType: 'number',
      operationType: 'range',
      isBucketed: true,
      scale: 'interval',
      params: {
        type: 'histogram',
        ranges: [{
          from: 0,
          to: 1000,
          label: ''
        }],
        maxBars: 'auto'
      }
    };
  }
  getFiltersColumn({
    label,
    paramFilters
  }) {
    return {
      label: label !== null && label !== void 0 ? label : 'Filters',
      dataType: 'string',
      operationType: 'filters',
      scale: 'ordinal',
      isBucketed: true,
      params: {
        filters: paramFilters
      }
    };
  }
  getNumberColumn({
    seriesConfig,
    label,
    sourceField,
    columnType,
    columnFilter,
    operationType
  }) {
    if (columnType === 'operation' || operationType) {
      if (operationType && ['median', 'average', 'sum', 'min', 'max', 'unique_count'].includes(operationType)) {
        return this.getNumberOperationColumn({
          sourceField,
          operationType: operationType,
          label,
          seriesConfig,
          columnFilter
        });
      }
      if (operationType === 'last_value') {
        return this.getLastValueOperationColumn({
          sourceField,
          operationType,
          label,
          seriesConfig,
          columnFilter
        });
      }
      if (operationType !== null && operationType !== void 0 && operationType.includes('th')) {
        return this.getPercentileNumberColumn(sourceField, operationType, seriesConfig, label);
      }
    }
    return this.getNumberRangeColumn(sourceField, seriesConfig, label);
  }
  getLastValueOperationColumn({
    sourceField,
    label,
    seriesConfig,
    operationType,
    columnFilter
  }) {
    return {
      ...buildNumberColumn(sourceField),
      operationType,
      label: label || seriesConfig.labels[sourceField],
      filter: columnFilter,
      params: {
        sortField: '@timestamp',
        showArrayValues: false
      }
    };
  }
  getNumberOperationColumn({
    sourceField,
    label,
    seriesConfig,
    operationType,
    columnFilter
  }) {
    return {
      ...buildNumberColumn(sourceField),
      label: label !== null && label !== void 0 ? label : _i18n.i18n.translate('xpack.exploratoryView.expView.columns.operation.label', {
        defaultMessage: '{operationType} of {sourceField}',
        values: {
          sourceField: seriesConfig.labels[sourceField],
          operationType: (0, _lodash.capitalize)(operationType)
        }
      }),
      customLabel: true,
      filter: columnFilter,
      operationType,
      params: operationType === 'unique_count' ? {
        emptyAsNull: true
      } : {}
    };
  }
  getPercentileBreakdowns(layerConfig, layerId, columnFilter) {
    const yAxisColumns = layerConfig.seriesConfig.yAxisColumns;
    const {
      sourceField: mainSourceField,
      label: mainLabel
    } = yAxisColumns[0];
    const lensColumns = {};

    // start at 1, because main y axis will have the first percentile breakdown
    for (let i = 1; i < _constants2.PERCENTILE_RANKS.length; i++) {
      lensColumns[`y-axis-column-${i}`] = {
        ...this.getColumnBasedOnType({
          sourceField: mainSourceField,
          operationType: _constants2.PERCENTILE_RANKS[i],
          label: mainLabel,
          layerConfig,
          layerId,
          colIndex: i
        }),
        filter: {
          query: columnFilter || '',
          language: 'kuery'
        }
      };
    }
    return lensColumns;
  }
  getPercentileNumberColumn(sourceField, percentileValue, seriesConfig, label) {
    var _seriesConfig$labels$2;
    return {
      ...buildNumberColumn(sourceField),
      label: label !== null && label !== void 0 ? label : _i18n.i18n.translate('xpack.exploratoryView.expView.columns.label', {
        defaultMessage: '{percentileValue} percentile of {sourceField}',
        values: {
          sourceField: (_seriesConfig$labels$2 = seriesConfig.labels[sourceField]) === null || _seriesConfig$labels$2 === void 0 ? void 0 : _seriesConfig$labels$2.toLowerCase(),
          percentileValue
        }
      }),
      operationType: 'percentile',
      params: getPercentileParam(percentileValue),
      customLabel: true
    };
  }
  getDateHistogramColumn(sourceField) {
    return {
      sourceField,
      dataType: 'date',
      isBucketed: true,
      label: '@timestamp',
      operationType: 'date_histogram',
      params: {
        interval: 'auto',
        includeEmptyRows: true
      },
      scale: 'interval'
    };
  }
  getTermsColumn(sourceField, label) {
    return {
      operationType: 'terms',
      sourceField,
      label: 'Top values of ' + label || sourceField,
      dataType: 'string',
      isBucketed: true,
      scale: 'ordinal',
      params: {
        size: 10,
        orderBy: {
          type: 'alphabetical',
          fallback: false
        },
        orderDirection: 'desc'
      }
    };
  }
  getXAxis(layerConfig, layerId) {
    const {
      xAxisColumn
    } = layerConfig.seriesConfig;
    let xSourceFiled = xAxisColumn === null || xAxisColumn === void 0 ? void 0 : xAxisColumn.sourceField;
    if (!xSourceFiled) {
      return [xAxisColumn];
    }
    if (xSourceFiled === _constants2.USE_BREAK_DOWN_COLUMN) {
      return this.getBreakdownColumn({
        layerId,
        layerConfig,
        sourceField: layerConfig.breakdown || layerConfig.seriesConfig.breakdownFields[0]
      });
    }
    if (xSourceFiled === _constants2.REPORT_METRIC_FIELD) {
      const {
        paramFilters
      } = this.getFieldMeta(xSourceFiled, layerConfig);
      if (paramFilters) {
        return this.getFiltersColumn({
          paramFilters
        });
      }
    }
    if (xSourceFiled === _constants2.REPORT_METRIC_TIMESTAMP) {
      const metricOption = parseCustomFieldName(layerConfig.seriesConfig, layerConfig.selectedMetricField);
      if (!Array.isArray(metricOption)) {
        const {
          timestampField = '@timestamp'
        } = metricOption;
        xSourceFiled = timestampField;
      }
    }
    return this.getColumnBasedOnType({
      layerConfig,
      layerId,
      label: xAxisColumn.label,
      sourceField: xSourceFiled
    });
  }
  getColumnBasedOnType({
    sourceField,
    label,
    layerConfig,
    operationType,
    colIndex,
    layerId,
    metricOption
  }) {
    const {
      breakdown,
      seriesConfig
    } = layerConfig;
    const fieldMetaInfo = this.getFieldMeta(sourceField, layerConfig, metricOption);
    const {
      format,
      formula,
      fieldMeta,
      columnType,
      fieldName,
      columnLabel,
      timeScale,
      columnFilters,
      showPercentileAnnotations
    } = fieldMetaInfo;
    if (columnType === _constants2.FORMULA_COLUMN) {
      return (0, _overall_column.getDistributionInPercentageColumn)({
        layerId,
        formula,
        format,
        label: columnLabel !== null && columnLabel !== void 0 ? columnLabel : label,
        dataView: layerConfig.dataView,
        lensFormulaHelper: this.lensFormulaHelper
      }).main;
    }
    if (showPercentileAnnotations) {
      this.addThresholdLayer(fieldName, layerId, layerConfig);
    }
    const {
      type: fieldType
    } = fieldMeta !== null && fieldMeta !== void 0 ? fieldMeta : {};
    if (columnType === _constants2.TERMS_COLUMN) {
      return this.getTermsColumn(fieldName, label || columnLabel);
    }
    if (fieldName === _constants2.RECORDS_FIELD || columnType === _constants2.FILTER_RECORDS) {
      return this.getRecordsColumn(label || columnLabel, colIndex !== undefined ? columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters[colIndex] : undefined, timeScale);
    }
    if (fieldType === 'date') {
      return this.getDateHistogramColumn(fieldName);
    }
    if (fieldType === 'number' && breakdown === _constants2.PERCENTILE) {
      return {
        ...this.getPercentileNumberColumn(fieldName, operationType || _constants2.PERCENTILE_RANKS[0], seriesConfig, label || columnLabel),
        filter: colIndex !== undefined ? columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters[colIndex] : undefined
      };
    }
    if (fieldType === 'number') {
      return this.getNumberColumn({
        sourceField: fieldName,
        columnType,
        columnFilter: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters[0],
        operationType,
        label: label || columnLabel,
        seriesConfig: layerConfig.seriesConfig
      });
    }
    if (operationType === 'unique_count' || fieldType === 'string') {
      return this.getNumberOperationColumn({
        sourceField: fieldName,
        operationType: 'unique_count',
        label: label || columnLabel,
        seriesConfig: layerConfig.seriesConfig,
        columnFilter: columnFilters === null || columnFilters === void 0 ? void 0 : columnFilters[0]
      });
    }

    // FIXME review my approach again
    return this.getDateHistogramColumn(fieldName);
  }
  getCustomFieldName({
    sourceField,
    layerConfig
  }) {
    return parseCustomFieldName(layerConfig.seriesConfig, sourceField);
  }
  getFieldMeta(sourceField, layerConfig, metricOpt) {
    if (sourceField === _constants2.REPORT_METRIC_FIELD) {
      var _layerConfig$showPerc;
      const metricOption = metricOpt ? {
        ...metricOpt,
        columnLabel: metricOpt.label,
        columnField: metricOpt.field,
        fieldName: metricOpt.field
      } : parseCustomFieldName(layerConfig.seriesConfig, layerConfig.selectedMetricField);
      if (Array.isArray(metricOption)) {
        return {
          fieldName: sourceField,
          items: metricOption
        };
      }
      const {
        palette,
        fieldName,
        columnType,
        columnLabel,
        columnFilters,
        timeScale,
        paramFilters,
        showPercentileAnnotations,
        formula,
        format
      } = metricOption;
      const fieldMeta = layerConfig.dataView.getFieldByName(fieldName);
      return {
        format,
        formula,
        palette,
        fieldMeta,
        fieldName,
        columnType,
        columnLabel,
        columnFilters,
        timeScale,
        paramFilters,
        showPercentileAnnotations: (_layerConfig$showPerc = layerConfig.showPercentileAnnotations) !== null && _layerConfig$showPerc !== void 0 ? _layerConfig$showPerc : showPercentileAnnotations
      };
    } else {
      const fieldMeta = layerConfig.dataView.getFieldByName(sourceField);
      return {
        fieldMeta,
        fieldName: sourceField
      };
    }
  }
  getMainYAxis(layerConfig, layerId, columnFilter) {
    const {
      breakdown
    } = layerConfig;
    const {
      sourceField,
      operationType,
      label: colLabel,
      timeScale
    } = layerConfig.seriesConfig.yAxisColumns[0];
    let label = layerConfig.name || colLabel;
    if (layerConfig.seriesConfig.reportType === _constants2.ReportTypes.CORE_WEB_VITAL) {
      label = colLabel;
    }
    if (sourceField === _constants2.RECORDS_PERCENTAGE_FIELD) {
      return [(0, _overall_column.getDistributionInPercentageColumn)({
        label,
        layerId,
        columnFilter,
        dataView: layerConfig.dataView,
        lensFormulaHelper: this.lensFormulaHelper
      }).main];
    }
    if (sourceField === _constants2.RECORDS_FIELD || !sourceField) {
      return [this.getRecordsColumn(label, undefined, timeScale)];
    }
    const fieldMetaInfo = this.getFieldMeta(sourceField, layerConfig);
    if (!fieldMetaInfo.fieldMeta && fieldMetaInfo.fieldName === _constants2.RECORDS_FIELD) {
      var _fieldMetaInfo$column;
      return [this.getRecordsColumn(label, (_fieldMetaInfo$column = fieldMetaInfo.columnFilters) === null || _fieldMetaInfo$column === void 0 ? void 0 : _fieldMetaInfo$column[0], timeScale)];
    }
    if ('items' in fieldMetaInfo) {
      const {
        items
      } = fieldMetaInfo;
      return items === null || items === void 0 ? void 0 : items.map((item, index) => {
        return this.getColumnBasedOnType({
          layerConfig,
          layerId,
          label: item.label,
          sourceField: _constants2.REPORT_METRIC_FIELD,
          metricOption: item,
          operationType: operationType
        });
      });
    }
    return [this.getColumnBasedOnType({
      sourceField,
      label,
      layerConfig,
      colIndex: 0,
      operationType: breakdown === _constants2.PERCENTILE ? _constants2.PERCENTILE_RANKS[0] : operationType,
      layerId
    })];
  }
  getChildYAxises(layerConfig, layerId, columnFilter, forAccessorsKeys) {
    const {
      breakdown
    } = layerConfig;
    const lensColumns = {};
    const yAxisColumns = layerConfig.seriesConfig.yAxisColumns;
    const {
      sourceField: mainSourceField,
      label: mainLabel
    } = yAxisColumns[0];
    if (mainSourceField === _constants2.RECORDS_PERCENTAGE_FIELD && layerId && !forAccessorsKeys) {
      return (0, _overall_column.getDistributionInPercentageColumn)({
        label: mainLabel,
        layerId,
        columnFilter,
        dataView: layerConfig.dataView,
        lensFormulaHelper: this.lensFormulaHelper
      }).supportingColumns;
    }
    if (mainSourceField && !forAccessorsKeys) {
      const {
        columnLabel,
        formula,
        columnType
      } = this.getFieldMeta(mainSourceField, layerConfig);
      if (columnType === _constants2.FORMULA_COLUMN) {
        return (0, _overall_column.getDistributionInPercentageColumn)({
          label: columnLabel,
          layerId,
          formula,
          dataView: layerConfig.dataView,
          lensFormulaHelper: this.lensFormulaHelper
        }).supportingColumns;
      }
    }
    if (yAxisColumns.length === 1 && breakdown === _constants2.PERCENTILE) {
      return this.getPercentileBreakdowns(layerConfig, layerId, columnFilter);
    }
    if (yAxisColumns.length === 1) {
      return lensColumns;
    }

    // starting from 1 index since 0 column is used as main column
    for (let i = 1; i < yAxisColumns.length; i++) {
      const {
        sourceField,
        operationType,
        label
      } = yAxisColumns[i];
      lensColumns[`y-axis-column-${i}`] = this.getColumnBasedOnType({
        sourceField: sourceField,
        operationType: operationType,
        label,
        layerConfig,
        colIndex: i,
        layerId
      });
    }
    return lensColumns;
  }
  getRecordsColumn(label, columnFilter, timeScale) {
    return {
      dataType: 'number',
      isBucketed: false,
      label: label || 'Count of records',
      customLabel: true,
      operationType: 'count',
      scale: 'ratio',
      sourceField: _constants2.RECORDS_FIELD,
      filter: columnFilter,
      ...(timeScale ? {
        timeScale
      } : {})
    };
  }
  getLayerFilters(layerConfig, totalLayers) {
    const {
      filters,
      time,
      seriesConfig: {
        baseFilters: layerFilters,
        reportType
      }
    } = layerConfig;
    let baseFilters = '';
    if (reportType !== _constants2.ReportTypes.KPI && totalLayers > 1 && time) {
      // for kpi over time, we don't need to add time range filters
      // since those are essentially plotted along the x-axis
      baseFilters += `@timestamp >= ${time.from} and @timestamp <= ${time.to}`;
    }
    layerFilters === null || layerFilters === void 0 ? void 0 : layerFilters.forEach(filter => {
      var _qFilter$query, _qFilter$query2, _qFilter$query2$bool;
      const qFilter = filter;
      if ((_qFilter$query = qFilter.query) !== null && _qFilter$query !== void 0 && _qFilter$query.match_phrase) {
        const fieldName = Object.keys(qFilter.query.match_phrase)[0];
        const kql = `${fieldName}: ${qFilter.query.match_phrase[fieldName]}`;
        if (baseFilters.length > 0) {
          baseFilters += ` and ${kql}`;
        } else {
          baseFilters += kql;
        }
      }
      if ((_qFilter$query2 = qFilter.query) !== null && _qFilter$query2 !== void 0 && (_qFilter$query2$bool = _qFilter$query2.bool) !== null && _qFilter$query2$bool !== void 0 && _qFilter$query2$bool.should) {
        var _qFilter$query3;
        const values = [];
        let fieldName = '';
        (_qFilter$query3 = qFilter.query) === null || _qFilter$query3 === void 0 ? void 0 : _qFilter$query3.bool.should.forEach(ft => {
          if (ft.match_phrase) {
            fieldName = Object.keys(ft.match_phrase)[0];
            values.push(ft.match_phrase[fieldName]);
          }
        });
        const kueryString = `${fieldName}: (${values.join(' or ')})`;
        if (baseFilters.length > 0) {
          baseFilters += ` and ${kueryString}`;
        } else {
          baseFilters += kueryString;
        }
      }
      const existFilter = filter;
      if ((0, _esQuery.isExistsFilter)(existFilter)) {
        var _existFilter$query$ex;
        const fieldName = (_existFilter$query$ex = existFilter.query.exists) === null || _existFilter$query$ex === void 0 ? void 0 : _existFilter$query$ex.field;
        const kql = `${fieldName} : *`;
        if (baseFilters.length > 0) {
          baseFilters += ` and ${kql}`;
        } else {
          baseFilters += kql;
        }
      }
    });
    const urlFilters = (0, _stringify_kueries.urlFiltersToKueryString)(filters !== null && filters !== void 0 ? filters : []);
    if (!baseFilters) {
      return urlFilters;
    }
    if (!urlFilters) {
      return baseFilters;
    }
    return `${urlFilters} and ${baseFilters}`;
  }
  getTimeShift(mainLayerConfig, layerConfig, index) {
    if (index === 0 || mainLayerConfig.seriesConfig.reportType !== _constants2.ReportTypes.KPI || !layerConfig.time) {
      return null;
    }
    const {
      time: {
        from: mainFrom
      }
    } = mainLayerConfig;
    const {
      time: {
        from
      }
    } = layerConfig;
    const parsedMainFrom = (0, _date_range_picker.parseRelativeDate)(mainFrom);
    const parsedFrom = (0, _date_range_picker.parseRelativeDate)(from);
    const inDays = parsedMainFrom && parsedFrom ? Math.abs(parsedMainFrom.diff(parsedFrom, 'days')) : 0;
    if (inDays > 1) {
      return inDays + 'd';
    }
    const inHours = parsedMainFrom && parsedFrom ? Math.abs(parsedMainFrom === null || parsedMainFrom === void 0 ? void 0 : parsedMainFrom.diff(parsedFrom, 'hours')) : 0;
    if (inHours === 0) {
      return null;
    }
    return inHours + 'h';
  }
  getLayers() {
    const layers = {};
    const layerConfigs = this.layerConfigs;
    layerConfigs.forEach((layerConfig, index) => {
      const {
        breakdown,
        seriesConfig
      } = layerConfig;
      const layerId = `layer${index}`;
      const columnFilter = this.getLayerFilters(layerConfig, layerConfigs.length);
      const timeShift = this.getTimeShift(this.layerConfigs[0], layerConfig, index);
      const mainYAxises = this.getMainYAxis(layerConfig, layerId, columnFilter);
      const {
        sourceField
      } = seriesConfig.xAxisColumn;
      const hasBreakdownColumn =
      // do nothing since this will be used a x axis source
      Boolean(breakdown && sourceField !== _constants2.USE_BREAK_DOWN_COLUMN && breakdown !== _constants2.PERCENTILE);
      layers[layerId] = this.getDataLayer({
        layerId,
        layerConfig,
        mainYAxises,
        columnFilter,
        timeShift,
        hasBreakdownColumn
      });
    });
    Object.entries(this.seriesReferenceLines).forEach(([id, {
      layerData
    }]) => {
      layers[id] = layerData;
    });
    return layers;
  }
  getDataLayer({
    hasBreakdownColumn,
    layerId,
    layerConfig,
    columnFilter,
    mainYAxises,
    timeShift
  }) {
    const allYAxisColumns = {};
    mainYAxises === null || mainYAxises === void 0 ? void 0 : mainYAxises.forEach((mainYAxis, index) => {
      var _mainYAxis$filter, _mainYAxis$filter2, _filterQuery;
      let filterQuery = columnFilter || ((_mainYAxis$filter = mainYAxis.filter) === null || _mainYAxis$filter === void 0 ? void 0 : _mainYAxis$filter.query);
      if (columnFilter && (_mainYAxis$filter2 = mainYAxis.filter) !== null && _mainYAxis$filter2 !== void 0 && _mainYAxis$filter2.query) {
        filterQuery = `${columnFilter} and ${mainYAxis.filter.query}`;
      }
      const label = timeShift ? `${mainYAxis.label}(${timeShift})` : mainYAxis.label;
      allYAxisColumns[`y-axis-column-${layerId}-${index}`] = {
        ...mainYAxis,
        label,
        filter: {
          query: (_filterQuery = filterQuery) !== null && _filterQuery !== void 0 ? _filterQuery : '',
          language: 'kuery'
        },
        ...(timeShift ? {
          timeShift
        } : {})
      };
    });
    const {
      breakdown
    } = layerConfig;
    const breakDownColumn = hasBreakdownColumn ? this.getBreakdownColumn({
      layerId,
      sourceField: breakdown,
      layerConfig
    }) : null;
    const xAxises = {
      [`x-axis-column-${layerId}`]: this.getXAxis(layerConfig, layerId)
    };
    return {
      columnOrder: [...(hasBreakdownColumn ? [`breakdown-column-${layerId}`] : []), ...Object.keys(xAxises), ...Object.keys(allYAxisColumns), ...Object.keys(this.getChildYAxises(layerConfig, layerId, columnFilter))],
      columns: {
        ...xAxises,
        ...allYAxisColumns,
        ...(hasBreakdownColumn ? {
          [`breakdown-column-${layerId}`]: breakDownColumn
        } : {}),
        ...this.getChildYAxises(layerConfig, layerId, columnFilter)
      },
      incompleteColumns: {}
    };
  }
  getXyState() {
    return {
      legend: {
        isVisible: true,
        showSingleSeries: true,
        position: 'right',
        legendSize: _constants.LegendSize.AUTO,
        shouldTruncate: false
      },
      valueLabels: 'hide',
      fittingFunction: 'Linear',
      curveType: 'CURVE_MONOTONE_X',
      axisTitlesVisibilitySettings: {
        x: false,
        yLeft: !this.isMultiSeries,
        yRight: !this.isMultiSeries
      },
      tickLabelsVisibilitySettings: {
        x: true,
        yLeft: true,
        yRight: true
      },
      gridlinesVisibilitySettings: {
        x: false,
        yLeft: true,
        yRight: true
      },
      preferredSeriesType: 'line',
      layers: this.getDataLayers(),
      ...(this.layerConfigs[0].seriesConfig.yTitle ? {
        yTitle: this.layerConfigs[0].seriesConfig.yTitle
      } : {})
    };
  }
  getDataLayers() {
    const dataLayers = this.layerConfigs.map((layerConfig, index) => {
      var _this$getMainYAxis, _palette, _layerConfig$dataView, _this$layerConfigs$0$;
      const {
        sourceField
      } = layerConfig.seriesConfig.yAxisColumns[0];
      let palette = layerConfig.seriesConfig.palette;
      if (sourceField) {
        const fieldMeta = this.getFieldMeta(sourceField, layerConfig);
        if (fieldMeta.palette) {
          palette = fieldMeta.palette;
        }
      }
      const layerId = `layer${index}`;
      const columnFilter = this.getLayerFilters(layerConfig, this.layerConfigs.length);
      const mainYAxises = (_this$getMainYAxis = this.getMainYAxis(layerConfig, layerId, columnFilter)) !== null && _this$getMainYAxis !== void 0 ? _this$getMainYAxis : [];
      return {
        accessors: [...mainYAxises.map((key, yIndex) => `y-axis-column-${layerId}-${yIndex}`), ...Object.keys(this.getChildYAxises(layerConfig, `layer${index}`, undefined, true))],
        layerId: `layer${index}`,
        layerType: 'data',
        seriesType: layerConfig.seriesType || layerConfig.seriesConfig.defaultSeriesType,
        palette: (_palette = palette) !== null && _palette !== void 0 ? _palette : layerConfig.seriesConfig.palette,
        yConfig: layerConfig.seriesConfig.yConfig || [{
          forAccessor: `y-axis-column-layer${index}-0`,
          color: layerConfig.color,
          /* if the fields format matches the field format of the first layer, use the default y axis (right)
           * if not, use the secondary y axis (left) */
          axisMode: ((_layerConfig$dataView = layerConfig.dataView.fieldFormatMap[layerConfig.selectedMetricField]) === null || _layerConfig$dataView === void 0 ? void 0 : _layerConfig$dataView.id) === ((_this$layerConfigs$0$ = this.layerConfigs[0].dataView.fieldFormatMap[this.layerConfigs[0].selectedMetricField]) === null || _this$layerConfigs$0$ === void 0 ? void 0 : _this$layerConfigs$0$.id) ? 'left' : 'right'
        }],
        xAccessor: `x-axis-column-layer${index}`,
        ...(layerConfig.breakdown && layerConfig.breakdown !== _constants2.PERCENTILE && layerConfig.seriesConfig.xAxisColumn.sourceField !== _constants2.USE_BREAK_DOWN_COLUMN ? {
          splitAccessor: `breakdown-column-layer${index}`
        } : {}),
        ...(this.layerConfigs[0].seriesConfig.yTitle ? {
          yTitle: this.layerConfigs[0].seriesConfig.yTitle
        } : {})
      };
    });
    const referenceLineLayers = [];
    Object.entries(this.seriesReferenceLines).forEach(([_id, {
      layerState
    }]) => {
      referenceLineLayers.push(layerState[0]);
    });
    return [...dataLayers, ...referenceLineLayers];
  }
  addThresholdLayer(fieldName, layerId, {
    seriesConfig,
    dataView
  }) {
    const referenceLineLayerId = `${layerId}-reference-lines`;
    const referenceLineColumns = this.getThresholdColumns(fieldName, referenceLineLayerId, seriesConfig);
    const layerData = {
      columnOrder: Object.keys(referenceLineColumns),
      columns: referenceLineColumns,
      incompleteColumns: {}
    };
    const layerState = this.getThresholdLayer(fieldName, referenceLineLayerId, seriesConfig);
    this.seriesReferenceLines[referenceLineLayerId] = {
      layerData,
      layerState,
      dataView
    };
  }
  getThresholdLayer(fieldName, referenceLineLayerId, seriesConfig) {
    const columns = this.getThresholdColumns(fieldName, referenceLineLayerId, seriesConfig);
    return [{
      layerId: referenceLineLayerId,
      accessors: Object.keys(columns),
      layerType: 'referenceLine',
      yConfig: Object.keys(columns).map(columnId => ({
        axisMode: 'bottom',
        color: '#6092C0',
        forAccessor: columnId,
        lineStyle: 'solid',
        lineWidth: 2,
        textVisibility: true
      }))
    }];
  }
  getThresholdColumns(fieldName, layerId, seriesConfig) {
    const referenceLines = ['50th', '75th', '90th', '95th', '99th'];
    const columns = {};
    referenceLines.forEach(referenceLine => {
      columns[`${referenceLine}-percentile-reference-line-${layerId}`] = {
        ...this.getPercentileNumberColumn(fieldName, referenceLine, seriesConfig),
        label: referenceLine
      };
    });
    return columns;
  }
  getReferences() {
    const uniqueIndexPatternsIds = Array.from(new Set([...this.layerConfigs.map(({
      dataView
    }) => dataView.id)]));
    const adHocDataViews = {};
    const referenceLineIndexReferences = Object.entries(this.seriesReferenceLines).map(([id, {
      dataView
    }]) => {
      adHocDataViews[dataView.id] = dataView.toSpec(false);
      return {
        id: dataView.id,
        name: getLayerReferenceName(id),
        type: 'index-pattern'
      };
    });
    const internalReferences = [...uniqueIndexPatternsIds.map(dataViewId => ({
      id: dataViewId,
      name: 'indexpattern-datasource-current-indexpattern',
      type: 'index-pattern'
    })), ...this.layerConfigs.map(({
      dataView
    }, index) => {
      adHocDataViews[dataView.id] = dataView.toSpec(false);
      return {
        id: dataView.id,
        name: getLayerReferenceName(`layer${index}`),
        type: 'index-pattern'
      };
    }), ...referenceLineIndexReferences];
    Object.entries(this.seriesReferenceLines).map(([id, {
      dataView
    }]) => ({
      id: dataView.id,
      name: getLayerReferenceName(id),
      type: 'index-pattern'
    }));
    return {
      internalReferences,
      adHocDataViews
    };
  }
  getJSON(visualizationType = 'lnsXY', lastRefresh) {
    const query = this.globalFilter || this.layerConfigs[0].seriesConfig.query;
    const {
      internalReferences,
      adHocDataViews
    } = this.getReferences();
    return {
      title: 'Prefilled from exploratory view app',
      description: lastRefresh ? `Last refreshed at ${new Date(lastRefresh).toISOString()}` : '',
      visualizationType,
      references: [],
      state: {
        internalReferences,
        adHocDataViews,
        datasourceStates: {
          formBased: {
            layers: this.layers
          }
        },
        visualization: this.visualization,
        query: query || {
          query: '',
          language: 'kuery'
        },
        filters: []
      }
    };
  }
}
exports.LensAttributes = LensAttributes;