import { uniqBy } from 'lodash';
import React, { useState, useRef } from 'react';
import { v4 } from 'uuid';
import { toOption } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { InlineField, Select } from '@grafana/ui';
import { InputGroup } from '../../QueryEditor/InputGroup.js';
import { AccessoryButton } from '../../QueryEditor/AccessoryButton.js';

const CONFLICTING_LABEL_FILTER_ERROR_MESSAGE = "You have conflicting label filters";
function LabelFilterItem({
  item,
  items,
  defaultOp,
  onChange,
  onDelete,
  onGetLabelNames,
  onGetLabelValues,
  invalidLabel,
  invalidValue,
  multiValueSeparator = "|"
}) {
  var _a;
  const [state, setState] = useState({});
  const [labelNamesMenuOpen, setLabelNamesMenuOpen] = useState(false);
  const [labelValuesMenuOpen, setLabelValuesMenuOpen] = useState(false);
  const isMultiSelect = (operator = item.op) => {
    var _a2;
    return (_a2 = operators.find((op) => op.label === operator)) == null ? undefined : _a2.isMultiValue;
  };
  const getSelectOptionsFromString = (item2) => {
    if (item2) {
      if (item2.indexOf(multiValueSeparator) > 0) {
        return item2.split(multiValueSeparator);
      }
      return [item2];
    }
    return [];
  };
  const getOptions = () => {
    const labelValues = state.labelValues ? [...state.labelValues] : [];
    const selectedOptions = getSelectOptionsFromString(item == null ? undefined : item.value).map(toOption);
    return uniqBy([...selectedOptions, ...labelValues], "value");
  };
  const isConflicting = isConflictingLabelFilter(item, items);
  const { current: id } = useRef(v4());
  return /* @__PURE__ */ React.createElement("div", { "data-testid": "visual-query-builder-dimensions-filter-item" }, /* @__PURE__ */ React.createElement(InlineField, { error: CONFLICTING_LABEL_FILTER_ERROR_MESSAGE, invalid: isConflicting ? true : undefined }, /* @__PURE__ */ React.createElement(InputGroup, null, /* @__PURE__ */ React.createElement(
    Select,
    {
      placeholder: "Select label",
      "data-testid": selectors.components.QueryBuilder.labelSelect,
      inputId: `visual-query-builder-dimensions-filter-item-key-${id}`,
      width: "auto",
      value: item.label ? toOption(item.label) : null,
      allowCustomValue: true,
      onOpenMenu: async () => {
        setState({ isLoadingLabelNames: true });
        const labelNames = await onGetLabelNames(item);
        setLabelNamesMenuOpen(true);
        setState({ labelNames, isLoadingLabelNames: undefined });
      },
      onCloseMenu: () => {
        setLabelNamesMenuOpen(false);
      },
      isOpen: labelNamesMenuOpen,
      isLoading: state.isLoadingLabelNames,
      options: state.labelNames,
      onChange: (change) => {
        var _a2;
        if (change.value) {
          onChange({
            ...item,
            op: (_a2 = item.op) != null ? _a2 : defaultOp,
            label: change.value
          });
        }
      },
      invalid: isConflicting || invalidLabel
    }
  ), /* @__PURE__ */ React.createElement(
    Select,
    {
      "data-testid": selectors.components.QueryBuilder.matchOperatorSelect,
      value: toOption((_a = item.op) != null ? _a : defaultOp),
      options: operators,
      width: "auto",
      onChange: (change) => {
        if (change.value) {
          onChange({
            ...item,
            op: change.value,
            value: isMultiSelect(change.value) ? item.value : getSelectOptionsFromString(item == null ? undefined : item.value)[0]
          });
        }
      },
      invalid: isConflicting
    }
  ), /* @__PURE__ */ React.createElement(
    Select,
    {
      placeholder: "Select value",
      "data-testid": selectors.components.QueryBuilder.valueSelect,
      inputId: `visual-query-builder-dimensions-filter-item-value-${id}`,
      width: "auto",
      value: isMultiSelect() ? getSelectOptionsFromString(item == null ? undefined : item.value).map(toOption) : getSelectOptionsFromString(item == null ? undefined : item.value).map(toOption)[0],
      allowCustomValue: true,
      onOpenMenu: async () => {
        setState({ isLoadingLabelValues: true });
        const labelValues = await onGetLabelValues(item);
        setState({
          ...state,
          labelValues,
          isLoadingLabelValues: undefined
        });
        setLabelValuesMenuOpen(true);
      },
      onCloseMenu: () => {
        setLabelValuesMenuOpen(false);
      },
      isOpen: labelValuesMenuOpen,
      isMulti: isMultiSelect(),
      isLoading: state.isLoadingLabelValues,
      options: getOptions(),
      onChange: (change) => {
        var _a2, _b;
        if (change.value) {
          onChange({
            ...item,
            value: change.value,
            op: (_a2 = item.op) != null ? _a2 : defaultOp
          });
        } else {
          const changes = change.map((change2) => {
            if (change2.value) {
              return change2.value;
            } else {
              return undefined;
            }
          }).filter((val) => val !== undefined).join(multiValueSeparator);
          onChange({ ...item, value: changes, op: (_b = item.op) != null ? _b : defaultOp });
        }
      },
      invalid: isConflicting || invalidValue
    }
  ), /* @__PURE__ */ React.createElement(AccessoryButton, { "aria-label": "remove", icon: "times", variant: "secondary", onClick: onDelete }))));
}
const operators = [
  { label: "=", value: "=", description: "Equals", isMultiValue: false },
  { label: "!=", value: "!=", description: "Does not equal", isMultiValue: false },
  { label: "=~", value: "=~", description: "Matches regex", isMultiValue: true },
  { label: "!~", value: "!~", description: "Does not match regex", isMultiValue: true }
];
function isConflictingLabelFilter(newLabel, labels) {
  if (!newLabel.label || !newLabel.op || !newLabel.value) {
    return false;
  }
  if (labels.length < 2) {
    return false;
  }
  const operationIsNegative = newLabel.op.toString().startsWith("!");
  const candidates = labels.filter(
    (label) => label.label === newLabel.label && label.value === newLabel.value && label.op !== newLabel.op
  );
  const conflict = candidates.some((candidate) => {
    var _a, _b;
    if (operationIsNegative && ((_a = candidate == null ? undefined : candidate.op) == null ? undefined : _a.toString().startsWith("!")) === false) {
      return true;
    }
    if (operationIsNegative === false && ((_b = candidate == null ? undefined : candidate.op) == null ? undefined : _b.toString().startsWith("!"))) {
      return true;
    }
    return false;
  });
  return conflict;
}

export { LabelFilterItem, isConflictingLabelFilter };
//# sourceMappingURL=LabelFilterItem.js.map
