import React, { useMemo } from 'react';
import { SceneObjectBase } from '../../core/SceneObjectBase.js';
import { SceneVariableValueChangedEvent } from '../types.js';
import { escapeOriginFilterUrlDelimiters, getQueriesForVariables, dataFromResponse, responseHasError, renderPrometheusLabelFilters } from '../utils.js';
import { patchGetAdhocFilters } from './patchGetAdhocFilters.js';
import { useStyles2 } from '@grafana/ui';
import { sceneGraph } from '../../core/sceneGraph/index.js';
import { AdHocFilterBuilder } from './AdHocFilterBuilder.js';
import { AdHocFilterRenderer } from './AdHocFilterRenderer.js';
import { getDataSourceSrv } from '@grafana/runtime';
import { AdHocFiltersVariableUrlSyncHandler, toArray } from './AdHocFiltersVariableUrlSyncHandler.js';
import { css } from '@emotion/css';
import { getEnrichedFiltersRequest } from '../getEnrichedFiltersRequest.js';
import { AdHocFiltersComboboxRenderer } from './AdHocFiltersCombobox/AdHocFiltersComboboxRenderer.js';
import { wrapInSafeSerializableSceneObject } from '../../utils/wrapInSafeSerializableSceneObject.js';
import { debounce, isEqual } from 'lodash';
import { getAdHocFiltersFromScopes } from './getAdHocFiltersFromScopes.js';
import { VariableDependencyConfig } from '../VariableDependencyConfig.js';
import { getQueryController } from '../../core/sceneGraph/getQueryController.js';
import { FILTER_RESTORED_INTERACTION, FILTER_REMOVED_INTERACTION } from '../../performance/interactionConstants.js';
import { AdHocFiltersVariableController } from './controller/AdHocFiltersVariableController.js';
import { AdHocFiltersRecommendations } from './AdHocFiltersRecommendations.js';

const ORIGIN_FILTERS_KEY = "originFilters";
const OPERATORS = [
  {
    value: "=",
    description: "Equals"
  },
  {
    value: "!=",
    description: "Not equal"
  },
  {
    value: "=|",
    description: "One of. Use to filter on multiple values.",
    isMulti: true
  },
  {
    value: "!=|",
    description: "Not one of. Use to exclude multiple values.",
    isMulti: true
  },
  {
    value: "=~",
    description: "Matches regex",
    isRegex: true
  },
  {
    value: "!~",
    description: "Does not match regex",
    isRegex: true
  },
  {
    value: "<",
    description: "Less than"
  },
  {
    value: "<=",
    description: "Less than or equal to"
  },
  {
    value: ">",
    description: "Greater than"
  },
  {
    value: ">=",
    description: "Greater than or equal to"
  }
];
class AdHocFiltersVariable extends SceneObjectBase {
  constructor(state) {
    var _a, _b, _c, _d, _e, _f;
    const behaviors = (_a = state.$behaviors) != null ? _a : [];
    const recommendations = state.drilldownRecommendationsEnabled ? new AdHocFiltersRecommendations() : void 0;
    if (recommendations) {
      behaviors.push(recommendations);
    }
    super({
      type: "adhoc",
      name: (_b = state.name) != null ? _b : "Filters",
      filters: [],
      datasource: null,
      applyMode: "auto",
      filterExpression: (_e = state.filterExpression) != null ? _e : renderExpression(state.expressionBuilder, [...(_c = state.originFilters) != null ? _c : [], ...(_d = state.filters) != null ? _d : []]),
      ...state,
      $behaviors: behaviors.length > 0 ? behaviors : void 0
    });
    this._scopedVars = { __sceneObject: wrapInSafeSerializableSceneObject(this) };
    this._dataSourceSrv = getDataSourceSrv();
    // holds the originalValues of all baseFilters in a map. The values
    // are set on construct and used to restore a baseFilter with an origin
    // to its original value if edited at some point
    this._originalValues = /* @__PURE__ */ new Map();
    this._prevScopes = [];
    /** Needed for scopes dependency */
    this._variableDependency = new VariableDependencyConfig(this, {
      dependsOnScopes: true,
      onReferencedVariableValueChanged: () => this._updateScopesFilters()
    });
    this._urlSync = new AdHocFiltersVariableUrlSyncHandler(this);
    this._debouncedVerifyApplicability = debounce(this._verifyApplicability, 100);
    this._activationHandler = () => {
      this._debouncedVerifyApplicability();
      return () => {
        var _a;
        (_a = this.state.originFilters) == null ? void 0 : _a.forEach((filter) => {
          if (filter.restorable && !isGroupByFilter(filter)) {
            this.restoreOriginalFilter(filter);
          }
        });
        this.restoreOriginalGroupBy();
      };
    };
    this._recommendations = recommendations;
    if (this.state.applyMode === "auto") {
      patchGetAdhocFilters(this);
    }
    (_f = this.state.originFilters) == null ? void 0 : _f.forEach((filter) => {
      this._setOriginalValue(filter);
    });
    this.addActivationHandler(this._activationHandler);
  }
  getRecommendations() {
    return this._recommendations;
  }
  _updateScopesFilters() {
    var _a, _b;
    const scopes = sceneGraph.getScopes(this);
    if (!scopes || !scopes.length) {
      this.setState({
        originFilters: (_a = this.state.originFilters) == null ? void 0 : _a.filter((filter) => filter.origin !== "scope")
      });
      return;
    }
    const scopeFilters = getAdHocFiltersFromScopes(scopes);
    if (!scopeFilters.length) {
      return;
    }
    let finalFilters = scopeFilters;
    const scopeInjectedFilters = [];
    const remainingFilters = [];
    finalFilters.forEach((scopeFilter) => {
      this._setOriginalValue(scopeFilter);
    });
    (_b = this.state.originFilters) == null ? void 0 : _b.forEach((filter) => {
      if (filter.origin === "scope") {
        scopeInjectedFilters.push(filter);
      } else {
        remainingFilters.push(filter);
      }
    });
    if (this._prevScopes.length) {
      this.setState({ originFilters: [...finalFilters, ...remainingFilters] });
      this._prevScopes = scopes;
      this._debouncedVerifyApplicability();
      return;
    }
    const editedScopeFilters = scopeInjectedFilters.filter((filter) => filter.restorable);
    const editedScopeFilterKeys = editedScopeFilters.map((filter) => filter.key);
    const scopeFilterKeys = scopeFilters.map((filter) => filter.key);
    finalFilters = [
      ...editedScopeFilters.filter((filter) => scopeFilterKeys.includes(filter.key)),
      ...scopeFilters.filter((filter) => !editedScopeFilterKeys.includes(filter.key))
    ];
    this.setState({ originFilters: [...finalFilters, ...remainingFilters] });
    this._prevScopes = scopes;
    this._debouncedVerifyApplicability();
  }
  async verifyApplicabilityAndStoreRecentFilter(update) {
    var _a;
    await this._verifyApplicability();
    (_a = this._recommendations) == null ? void 0 : _a.storeRecentFilter(update);
  }
  setState(update) {
    var _a, _b, _c;
    let filterExpressionChanged = false;
    let groupByChanged = false;
    if ((update.filters && update.filters !== this.state.filters || update.originFilters && update.originFilters !== this.state.originFilters) && !update.filterExpression) {
      const filters = (_a = update.filters) != null ? _a : this.state.filters;
      const originFilters = (_b = update.originFilters) != null ? _b : this.state.originFilters;
      update.filterExpression = renderExpression(this.state.expressionBuilder, [...originFilters != null ? originFilters : [], ...filters]);
      filterExpressionChanged = update.filterExpression !== this.state.filterExpression;
      groupByChanged = haveGroupByKeysChanged(
        [...(_c = this.state.originFilters) != null ? _c : [], ...this.state.filters],
        [...originFilters != null ? originFilters : [], ...filters]
      );
    }
    super.setState(update);
    if (filterExpressionChanged || groupByChanged) {
      this.publishEvent(new SceneVariableValueChangedEvent(this), true);
    }
  }
  _resolveOriginFlags(key, origin, values, operator, singleValue) {
    const original = this._originalValues.get(originalValueKey({ key, origin, operator }));
    const isMatchAll = operator === "=~" && singleValue === ".*";
    const isRestorable = !isEqual(values, original == null ? void 0 : original.value) || operator !== (original == null ? void 0 : original.operator);
    return {
      matchAllFilter: isMatchAll,
      restorable: isRestorable
    };
  }
  validateOriginFilters(filters) {
    return filters.map((filter) => {
      if (!filter.origin) {
        return filter;
      }
      if (!this._originalValues.has(originalValueKey(filter))) {
        return filter;
      }
      const updateValues = filter.values || (filter.value ? [filter.value] : void 0);
      if (!updateValues) {
        return {
          ...filter,
          operator: "=~",
          value: ".*",
          values: [".*"],
          valueLabels: ["All"],
          matchAllFilter: true,
          nonApplicable: false,
          restorable: true
        };
      }
      const flags = this._resolveOriginFlags(filter.key, filter.origin, updateValues, filter.operator, filter.value);
      return { ...filter, ...flags };
    });
  }
  /**
   * Updates the variable's `filters` and `filterExpression` state.
   * If `skipPublish` option is true, this will not emit the `SceneVariableValueChangedEvent`,
   * allowing consumers to update the filters without triggering dependent data providers.
   */
  updateFilters(filters, options) {
    var _a;
    let filterExpressionChanged = false;
    let groupByChanged = false;
    let filterExpression = void 0;
    if (filters && filters !== this.state.filters) {
      filterExpression = renderExpression(this.state.expressionBuilder, [
        ...(_a = this.state.originFilters) != null ? _a : [],
        ...filters
      ]);
      filterExpressionChanged = filterExpression !== this.state.filterExpression;
      groupByChanged = haveGroupByKeysChanged(this.state.filters, filters);
    }
    super.setState({
      filters,
      filterExpression
    });
    if ((filterExpressionChanged || groupByChanged) && (options == null ? void 0 : options.skipPublish) !== true || (options == null ? void 0 : options.forcePublish)) {
      this.publishEvent(new SceneVariableValueChangedEvent(this), true);
    }
  }
  /**
   * Add a group-by filter (key only, operator 'groupBy', no value).
   * No-op when enableGroupBy is false.
   */
  _addGroupByFilter(item) {
    var _a, _b, _c;
    if (!this.state.enableGroupBy) {
      return;
    }
    const key = (_a = item.value) != null ? _a : "";
    const keyLabel = (_b = item.label) != null ? _b : key;
    const newFilter = {
      key,
      keyLabel,
      operator: "groupBy",
      value: "",
      condition: ""
    };
    (_c = this._recommendations) == null ? void 0 : _c.storeRecentGrouping(key);
    this.updateFilters([...this.state.filters, newFilter]);
  }
  restoreOriginalFilter(filter) {
    var _a;
    if (!filter.restorable) {
      return;
    }
    const originalFilter = this._originalValues.get(originalValueKey(filter));
    if (!originalFilter) {
      return;
    }
    const queryController = getQueryController(this);
    queryController == null ? void 0 : queryController.startProfile(FILTER_RESTORED_INTERACTION);
    this._updateFilter(filter, {
      value: originalFilter.value[0],
      values: isMultiValueOperator(originalFilter.operator) ? originalFilter.value : void 0,
      valueLabels: (_a = originalFilter.valueLabels) != null ? _a : originalFilter.value,
      operator: originalFilter.operator,
      nonApplicable: originalFilter.nonApplicable
    });
  }
  /**
   * Get the original value for an origin filter before any user modifications.
   * Returns undefined if no original is tracked for this filter.
   */
  getOriginalValue(filter) {
    return this._originalValues.get(originalValueKey(filter));
  }
  /**
   * Store a snapshot of the filter's current value and operator so it can be restored later.
   */
  _setOriginalValue(filter) {
    var _a;
    this._originalValues.set(originalValueKey(filter), {
      value: (_a = filter.values) != null ? _a : [filter.value],
      operator: filter.operator,
      ...filter.valueLabels && { valueLabels: filter.valueLabels },
      ...filter.keyLabel && { keyLabel: filter.keyLabel }
    });
  }
  /**
   * Get original filters from original values.
   * Returns filters from _originalValues map.
   */
  getOriginalFilters() {
    return [...this._originalValues.entries()].map(([mapKey, original]) => {
      var _a, _b;
      const suffix = `${VALUE_KEY_DELIMITER}${GROUP_BY_OPERATOR}`;
      const isGroupBy = mapKey.endsWith(suffix);
      const baseKey = isGroupBy ? mapKey.slice(0, -suffix.length) : mapKey;
      const delimiter = baseKey.lastIndexOf(VALUE_KEY_DELIMITER);
      const key = baseKey.substring(0, delimiter);
      const origin = baseKey.substring(delimiter + VALUE_KEY_DELIMITER.length);
      return {
        key,
        origin,
        value: original.value[0],
        values: isMultiValueOperator(original.operator) ? original.value : void 0,
        valueLabels: (_a = original.valueLabels) != null ? _a : original.value,
        keyLabel: (_b = original.keyLabel) != null ? _b : key,
        operator: original.operator,
        nonApplicable: original.nonApplicable
      };
    });
  }
  /**
   * Replace all stored original values from the given filters array.
   */
  setOriginalFilters(filters) {
    this._originalValues.clear();
    filters.forEach((filter) => {
      this._setOriginalValue(filter);
    });
  }
  /**
   * Whether the groupBy state has diverged from defaults (any dismissed or user-added groupBys).
   */
  isGroupByRestorable() {
    var _a;
    const originFilters = (_a = this.state.originFilters) != null ? _a : [];
    const hasOriginGroupBy = originFilters.some((f) => isGroupByFilter(f) && f.origin);
    if (!hasOriginGroupBy) {
      return false;
    }
    const hasDismissedOrRestorable = originFilters.some((f) => isGroupByFilter(f) && f.origin && f.restorable);
    const hasUserGroupBy = this.state.filters.some(isGroupByFilter);
    return hasDismissedOrRestorable || hasUserGroupBy;
  }
  /**
   * Restore all original group by filters.
   */
  restoreOriginalGroupBy() {
    var _a;
    const restoredOrigins = ((_a = this.state.originFilters) != null ? _a : []).map((f) => {
      if (!isGroupByFilter(f) || !f.origin) {
        return f;
      }
      return { ...f, dismissedGroupBy: false, restorable: false };
    });
    const nonGroupByFilters = this.state.filters.filter((f) => !isGroupByFilter(f));
    this.setState({
      originFilters: restoredOrigins,
      filters: nonGroupByFilters
    });
  }
  /**
   * Clear all user-added filters and restore origin filters to their original values.
   */
  clearAll() {
    var _a;
    (_a = this.state.originFilters) == null ? void 0 : _a.forEach((filter) => {
      if (filter.restorable && !isGroupByFilter(filter)) {
        this.restoreOriginalFilter(filter);
      }
    });
    this.restoreOriginalGroupBy();
    this.setState({ filters: [] });
  }
  getValue(fieldPath) {
    if (fieldPath === ORIGIN_FILTERS_KEY) {
      const originFilters = this.state.originFilters;
      if (!originFilters || (originFilters == null ? void 0 : originFilters.length) === 0) {
        return [];
      }
      return [
        ...originFilters.map(
          (filter) => toArray(filter).map(escapeOriginFilterUrlDelimiters).join("|").concat(`#${filter.origin}`)
        )
      ];
    }
    return this.state.filterExpression;
  }
  _updateFilter(filter, update) {
    var _a, _b, _c, _d, _e, _f;
    const { originFilters, filters, _wip } = this.state;
    if ("value" in update && !("values" in update)) {
      update = { ...update, values: void 0 };
    }
    if (filter.origin) {
      if (isGroupByFilter(filter) && "key" in update && update.key !== filter.key) {
        const updatedOrigins = (originFilters != null ? originFilters : []).map((f) => {
          if (f === filter) {
            return { ...f, dismissedGroupBy: true, restorable: true };
          }
          if (isGroupByFilter(f) && f.origin && !f.dismissedGroupBy) {
            return { ...f, restorable: true };
          }
          return f;
        });
        const newFilter = {
          key: update.key,
          keyLabel: (_a = update.keyLabel) != null ? _a : update.key,
          operator: "groupBy",
          value: "",
          condition: ""
        };
        this.setState({
          originFilters: updatedOrigins,
          filters: [...filters, newFilter]
        });
        return;
      }
      const updateValues = update.values || (update.value ? [update.value] : void 0);
      if (updateValues) {
        const effectiveOperator = (_b = update.operator) != null ? _b : filter.operator;
        const effectiveValue = (_c = update.value) != null ? _c : filter.value;
        const flags = this._resolveOriginFlags(
          filter.key,
          filter.origin,
          updateValues,
          effectiveOperator,
          effectiveValue
        );
        Object.assign(update, flags);
      }
      const updatedFilters2 = (_d = originFilters == null ? void 0 : originFilters.map((f) => {
        if (f === filter) {
          return { ...f, ...update };
        }
        if (isGroupByFilter(filter) && update.restorable && isGroupByFilter(f) && f.origin && !f.restorable) {
          return { ...f, restorable: true };
        }
        return f;
      })) != null ? _d : [];
      this.setState({ originFilters: updatedFilters2 });
      return;
    }
    if (filter === _wip) {
      if ("value" in update && update["value"] !== "") {
        this.setState({
          filters: [...filters, { ..._wip, ...update }],
          _wip: void 0
        });
        this.verifyApplicabilityAndStoreRecentFilter({ ..._wip, ...update });
      } else {
        this.setState({ _wip: { ...filter, ...update } });
      }
      return;
    }
    const updatedFilters = this.state.filters.map((f) => {
      return f === filter ? { ...f, ...update } : f;
    });
    this.setState({ filters: updatedFilters });
    const merged = { ...filter, ...update };
    if (isGroupByFilter(merged)) {
      (_e = this._recommendations) == null ? void 0 : _e.storeRecentGrouping(merged.key);
    } else {
      (_f = this._recommendations) == null ? void 0 : _f.storeRecentFilter(merged);
    }
  }
  updateToMatchAll(filter) {
    var _a;
    if (isGroupByFilter(filter) && filter.origin) {
      const updatedOrigins = ((_a = this.state.originFilters) != null ? _a : []).map((f) => {
        if (f === filter) {
          return { ...f, dismissedGroupBy: true, restorable: true };
        }
        if (isGroupByFilter(f) && f.origin && !f.dismissedGroupBy) {
          return { ...f, restorable: true };
        }
        return f;
      });
      this.setState({ originFilters: updatedOrigins });
    } else {
      this._updateFilter(filter, {
        operator: "=~",
        value: ".*",
        values: [".*"],
        valueLabels: ["All"],
        matchAllFilter: true,
        nonApplicable: false,
        restorable: true
      });
    }
  }
  _removeFilter(filter) {
    if (filter === this.state._wip) {
      this.setState({ _wip: void 0 });
      return;
    }
    const queryController = getQueryController(this);
    queryController == null ? void 0 : queryController.startProfile(FILTER_REMOVED_INTERACTION);
    this.setState({ filters: this.state.filters.filter((f) => f !== filter) });
    this._debouncedVerifyApplicability();
  }
  _removeLastFilter() {
    const filterToRemove = this.state.filters.at(-1);
    if (filterToRemove) {
      this._removeFilter(filterToRemove);
    }
  }
  _handleComboboxBackspace(filter) {
    var _a, _b;
    if (isGroupByFilter(filter)) {
      if (this.state.filters.includes(filter)) {
        this._removeFilter(filter);
      } else {
        for (let i = this.state.filters.length - 1; i >= 0; i--) {
          if (isGroupByFilter(this.state.filters[i]) && !this.state.filters[i].readOnly) {
            this._removeFilter(this.state.filters[i]);
            return;
          }
        }
        const origins = (_a = this.state.originFilters) != null ? _a : [];
        for (let i = origins.length - 1; i >= 0; i--) {
          if (isGroupByFilter(origins[i]) && origins[i].origin && !origins[i].dismissedGroupBy) {
            this.updateToMatchAll(origins[i]);
            return;
          }
        }
      }
      return;
    }
    if (isFilterComplete(filter)) {
      const queryController = getQueryController(this);
      queryController == null ? void 0 : queryController.startProfile(FILTER_REMOVED_INTERACTION);
    }
    const isWip = filter === this.state._wip;
    if (this.state.filters.length) {
      const filterToForceIndex = isWip ? findLastAdhocFilterIndex(this.state.filters) : -1;
      this.setState({
        filters: this.state.filters.reduce((acc, f, index) => {
          if (index === filterToForceIndex && !f.readOnly) {
            return [...acc, { ...f, forceEdit: true }];
          }
          if (f === filter) {
            return acc;
          }
          return [...acc, f];
        }, [])
      });
    } else if ((_b = this.state.originFilters) == null ? void 0 : _b.length) {
      const filterToForceIndex = isWip ? findLastAdhocFilterIndex(this.state.originFilters) : -1;
      this.setState({
        originFilters: this.state.originFilters.reduce((acc, f, index) => {
          if (index === filterToForceIndex && !f.readOnly) {
            return [...acc, { ...f, forceEdit: true }];
          }
          if (f === filter) {
            return acc;
          }
          return [...acc, f];
        }, [])
      });
    }
  }
  async getFiltersApplicabilityForQueries(filters, queries, groupByKeys) {
    const ds = await this._dataSourceSrv.get(this.state.datasource, this._scopedVars);
    if (!ds || !ds.getDrilldownsApplicability) {
      return;
    }
    const timeRange = sceneGraph.getTimeRange(this).state.value;
    return await ds.getDrilldownsApplicability({
      filters,
      queries,
      timeRange,
      scopes: sceneGraph.getScopes(this),
      ...groupByKeys && groupByKeys.length > 0 ? { groupByKeys } : {},
      ...getEnrichedFiltersRequest(this)
    });
  }
  async _verifyApplicability() {
    var _a, _b, _c;
    if (!this.state.applicabilityEnabled) {
      return;
    }
    const allFilters = [...this.state.filters, ...(_a = this.state.originFilters) != null ? _a : []];
    const filters = allFilters.filter((f) => !isGroupByFilter(f));
    const groupByKeys = this.state.enableGroupBy ? allFilters.filter((f) => isGroupByFilter(f)).map((f) => f.key) : void 0;
    const queries = this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
    const response = await this.getFiltersApplicabilityForQueries(filters, queries != null ? queries : [], groupByKeys);
    if (!response) {
      return;
    }
    const responseMap = /* @__PURE__ */ new Map();
    response.forEach((filter) => {
      responseMap.set(`${filter.key}${filter.origin ? `-${filter.origin}` : ""}`, filter);
    });
    const update = {
      filters: [...this.state.filters],
      originFilters: [...(_b = this.state.originFilters) != null ? _b : []]
    };
    update.filters.forEach((f) => {
      const filter = responseMap.get(f.key);
      if (filter) {
        f.nonApplicable = !filter.applicable;
        f.nonApplicableReason = filter.reason;
      }
    });
    (_c = update.originFilters) == null ? void 0 : _c.forEach((f) => {
      const filter = responseMap.get(`${f.key}-${f.origin}`);
      if (filter) {
        if (!f.matchAllFilter) {
          f.nonApplicable = !filter.applicable;
          f.nonApplicableReason = filter.reason;
        }
        const originalValue = this._originalValues.get(originalValueKey(f));
        if (originalValue) {
          originalValue.nonApplicable = !filter.applicable;
          originalValue.nonApplicableReason = filter == null ? void 0 : filter.reason;
        }
      }
    });
    this.setState(update);
  }
  /**
   * Get possible keys given current filters. Do not call from plugins directly
   */
  async _getKeys(currentKey) {
    var _a, _b, _c, _d, _e;
    const override = await ((_b = (_a = this.state).getTagKeysProvider) == null ? void 0 : _b.call(_a, this, currentKey));
    if (override && override.replace) {
      return dataFromResponse(override.values).map(toSelectableValue);
    }
    if (this.state.defaultKeys) {
      return this.state.defaultKeys.map(toSelectableValue);
    }
    const ds = await this._dataSourceSrv.get(this.state.datasource, this._scopedVars);
    if (!ds || !ds.getTagKeys) {
      return [];
    }
    const applicableOriginFilters = (_d = (_c = this.state.originFilters) == null ? void 0 : _c.filter((f) => !f.nonApplicable && !isGroupByFilter(f) && !isMatchAllFilter(f))) != null ? _d : [];
    const otherFilters = this.state.filters.filter((f) => f.key !== currentKey && !f.nonApplicable && !isGroupByFilter(f) && !isMatchAllFilter(f)).concat((_e = this.state.baseFilters) != null ? _e : []).concat(applicableOriginFilters);
    const timeRange = sceneGraph.getTimeRange(this).state.value;
    const queries = this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
    const response = await ds.getTagKeys({
      filters: otherFilters,
      queries,
      timeRange,
      scopes: sceneGraph.getScopes(this),
      ...getEnrichedFiltersRequest(this)
    });
    if (responseHasError(response)) {
      this.setState({ error: response.error.message });
    }
    let keys = dataFromResponse(response);
    if (override) {
      keys = keys.concat(dataFromResponse(override.values));
    }
    const tagKeyRegexFilter = this.state.tagKeyRegexFilter;
    if (tagKeyRegexFilter) {
      keys = keys.filter((f) => f.text.match(tagKeyRegexFilter));
    }
    return keys.map(toSelectableValue);
  }
  /**
   * Get possible group-by keys.
   * @param currentKey - The current key being edited (excluded from filters)
   * @param queries - Optional queries to scope the key lookup. When provided, these are used
   *   instead of discovering all queries in the scene via getQueriesForVariables.
   */
  async _getGroupByKeys(currentKey, queries) {
    var _a, _b, _c, _d, _e;
    if (!this.state.enableGroupBy) {
      return [];
    }
    const override = await ((_b = (_a = this.state).getGroupByKeysProvider) == null ? void 0 : _b.call(_a, this, currentKey));
    if (override && override.replace) {
      return dataFromResponse(override.values).map(toSelectableValue);
    }
    const ds = await this._dataSourceSrv.get(this.state.datasource, this._scopedVars);
    if (!ds || !ds.getGroupByKeys) {
      return override ? dataFromResponse(override.values).map(toSelectableValue) : [];
    }
    const applicableOriginFilters = (_d = (_c = this.state.originFilters) == null ? void 0 : _c.filter((f) => !f.nonApplicable && !isGroupByFilter(f) && !isMatchAllFilter(f))) != null ? _d : [];
    const otherFilters = this.state.filters.filter((f) => f.key !== currentKey && !f.nonApplicable && !isGroupByFilter(f) && !isMatchAllFilter(f)).concat((_e = this.state.baseFilters) != null ? _e : []).concat(applicableOriginFilters);
    const timeRange = sceneGraph.getTimeRange(this).state.value;
    const queriesForKeys = queries != null ? queries : this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
    const response = await ds.getGroupByKeys({
      filters: otherFilters,
      queries: queriesForKeys,
      timeRange,
      scopes: sceneGraph.getScopes(this),
      ...getEnrichedFiltersRequest(this)
    });
    if (responseHasError(response)) {
      this.setState({ error: response.error.message });
    }
    let keys = dataFromResponse(response);
    if (override) {
      keys = keys.concat(dataFromResponse(override.values));
    }
    const tagKeyRegexFilter = this.state.tagKeyRegexFilter;
    if (tagKeyRegexFilter) {
      keys = keys.filter((f) => f.text.match(tagKeyRegexFilter));
    }
    return keys.map(toSelectableValue);
  }
  /**
   * Get possible key values for a specific key given current filters. Do not call from plugins directly
   */
  async _getValuesFor(filter) {
    var _a, _b, _c, _d;
    const override = await ((_b = (_a = this.state).getTagValuesProvider) == null ? void 0 : _b.call(_a, this, filter));
    if (override && override.replace) {
      return dataFromResponse(override.values).map(toSelectableValue);
    }
    const ds = await this._dataSourceSrv.get(this.state.datasource, this._scopedVars);
    if (!ds || !ds.getTagValues) {
      return [];
    }
    const originFilters = (_d = (_c = this.state.originFilters) == null ? void 0 : _c.filter((f) => f.key !== filter.key && !isGroupByFilter(f) && !isMatchAllFilter(f))) != null ? _d : [];
    const otherFilters = this.state.filters.filter((f) => f.key !== filter.key && !isGroupByFilter(f) && !isMatchAllFilter(f)).concat(originFilters);
    const timeRange = sceneGraph.getTimeRange(this).state.value;
    const queries = this.state.useQueriesAsFilterForOptions ? getQueriesForVariables(this) : void 0;
    let scopes = sceneGraph.getScopes(this);
    if (filter.origin === "scope") {
      scopes = scopes == null ? void 0 : scopes.map((scope) => {
        var _a2;
        return {
          ...scope,
          spec: {
            ...scope.spec,
            filters: (_a2 = scope.spec.filters) == null ? void 0 : _a2.filter((f) => f.key !== filter.key)
          }
        };
      });
    }
    const response = await ds.getTagValues({
      key: filter.key,
      filters: otherFilters,
      timeRange,
      queries,
      scopes,
      ...getEnrichedFiltersRequest(this)
    });
    if (responseHasError(response)) {
      this.setState({ error: response.error.message });
    }
    let values = dataFromResponse(response);
    if (override) {
      values = values.concat(dataFromResponse(override.values));
    }
    return values.map(toSelectableValue);
  }
  _addWip() {
    this.setState({
      _wip: { key: "", value: "", operator: "=", condition: "" }
    });
  }
  _getOperators() {
    const { supportsMultiValueOperators, allowCustomValue = true } = this.state;
    return OPERATORS.filter(({ isMulti, isRegex }) => {
      if (!supportsMultiValueOperators && isMulti) {
        return false;
      }
      if (!allowCustomValue && isRegex) {
        return false;
      }
      return true;
    }).map(({ value, description }) => ({
      label: value,
      value,
      description
    }));
  }
}
AdHocFiltersVariable.Component = AdHocFiltersVariableRenderer;
function renderExpression(builder, filters) {
  var _a;
  return (builder != null ? builder : renderPrometheusLabelFilters)(
    (_a = filters == null ? void 0 : filters.filter((f) => isFilterApplicable(f) && !isGroupByFilter(f))) != null ? _a : []
  );
}
function getGroupByKeys(filters) {
  return filters.filter((f) => isGroupByFilter(f) && isFilterComplete(f) && !f.dismissedGroupBy).map((f) => f.key).sort();
}
function haveGroupByKeysChanged(prev, next) {
  const prevKeys = getGroupByKeys(prev);
  const nextKeys = getGroupByKeys(next);
  if (prevKeys.length !== nextKeys.length) {
    return true;
  }
  return prevKeys.some((key, i) => key !== nextKeys[i]);
}
function AdHocFiltersVariableRenderer({ model }) {
  const { filters, readOnly, addFilterButtonText } = model.useState();
  const styles = useStyles2(getStyles);
  const controller = useMemo(
    () => model.state.layout === "combobox" ? new AdHocFiltersVariableController(model) : void 0,
    [model]
  );
  if (controller) {
    return /* @__PURE__ */ React.createElement(AdHocFiltersComboboxRenderer, { controller });
  }
  return /* @__PURE__ */ React.createElement("div", { className: styles.wrapper }, filters.filter((filter) => !filter.hidden).map((filter, index) => /* @__PURE__ */ React.createElement(React.Fragment, { key: index }, /* @__PURE__ */ React.createElement(AdHocFilterRenderer, { filter, model }))), !readOnly && /* @__PURE__ */ React.createElement(AdHocFilterBuilder, { model, key: "'builder", addFilterButtonText }));
}
const getStyles = (theme) => ({
  wrapper: css({
    display: "flex",
    flexWrap: "wrap",
    alignItems: "flex-end",
    columnGap: theme.spacing(2),
    rowGap: theme.spacing(1)
  })
});
function toSelectableValue(input) {
  const { text, value } = input;
  const result = {
    // converting text to string due to some edge cases where it can be a number
    // TODO: remove once https://github.com/grafana/grafana/issues/99021 is closed
    label: String(text),
    value: String(value != null ? value : text)
  };
  if ("group" in input) {
    result.group = input.group;
  }
  if ("meta" in input) {
    result.meta = input.meta;
  }
  return result;
}
function isMatchAllFilter(filter) {
  return filter.operator === "=~" && filter.value === ".*";
}
const GROUP_BY_OPERATOR = "groupBy";
const VALUE_KEY_DELIMITER = "::";
function isGroupByFilter(filter) {
  return filter.operator === GROUP_BY_OPERATOR;
}
function isFilterComplete(filter) {
  return filter.key !== "" && filter.operator !== "" && (isGroupByFilter(filter) || filter.value !== "");
}
function isFilterApplicable(filter) {
  return !filter.nonApplicable;
}
function findLastAdhocFilterIndex(filters) {
  for (let i = filters.length - 1; i >= 0; i--) {
    if (!isGroupByFilter(filters[i])) {
      return i;
    }
  }
  return -1;
}
function originalValueKey({ key, origin, operator }) {
  return operator === GROUP_BY_OPERATOR ? `${key}${VALUE_KEY_DELIMITER}${origin}${VALUE_KEY_DELIMITER}${GROUP_BY_OPERATOR}` : `${key}${VALUE_KEY_DELIMITER}${origin}`;
}
function isMultiValueOperator(operatorValue) {
  const operator = OPERATORS.find((o) => o.value === operatorValue);
  if (!operator) {
    return false;
  }
  return Boolean(operator.isMulti);
}

export { AdHocFiltersVariable, AdHocFiltersVariableRenderer, GROUP_BY_OPERATOR, OPERATORS, VALUE_KEY_DELIMITER, isFilterApplicable, isFilterComplete, isGroupByFilter, isMatchAllFilter, isMultiValueOperator, toSelectableValue };
//# sourceMappingURL=AdHocFiltersVariable.js.map
