import { t } from '@grafana/i18n';
import React, { useState, useMemo } from 'react';
import { isMultiValueOperator, OPERATORS } from './AdHocFiltersVariable.js';
import { useStyles2, Select, Field, Button } from '@grafana/ui';
import { cx, css } from '@emotion/css';
import { ControlsLabel } from '../../utils/ControlsLabel.js';
import { getAdhocOptionSearcher } from './getAdhocOptionSearcher.js';
import { handleOptionGroups } from '../utils.js';
import { OptionWithCheckbox } from '../components/VariableValueSelect.js';

function keyLabelToOption(key, label) {
  return key !== "" ? {
    value: key,
    label: label || key
  } : null;
}
const filterNoOp$1 = () => true;
function AdHocFilterRenderer({ filter, model }) {
  var _a, _b, _c, _d, _e;
  const styles = useStyles2(getStyles$k);
  const [keys, setKeys] = useState([]);
  const [values, setValues] = useState([]);
  const [isKeysLoading, setIsKeysLoading] = useState(false);
  const [isValuesLoading, setIsValuesLoading] = useState(false);
  const [isKeysOpen, setIsKeysOpen] = useState(false);
  const [isValuesOpen, setIsValuesOpen] = useState(false);
  const [isOperatorOpen, setIsOperatorOpen] = useState(false);
  const [valueInputValue, setValueInputValue] = useState("");
  const [valueHasCustomValue, setValueHasCustomValue] = useState(false);
  const [uncommittedValue, setUncommittedValue] = useState(
    filter.values ? filter.values.map((value, index) => {
      var _a2;
      return keyLabelToOption(value, (_a2 = filter.valueLabels) == null ? void 0 : _a2[index]);
    }) : []
  );
  const isMultiValue = isMultiValueOperator(filter.operator);
  const keyValue = keyLabelToOption(filter.key, filter.keyLabel);
  const valueValue = keyLabelToOption(filter.value, (_a = filter.valueLabels) == null ? void 0 : _a[0]);
  const optionSearcher = useMemo(() => getAdhocOptionSearcher(values), [values]);
  const onAddCustomValue = model.state.onAddCustomValue;
  const onValueInputChange = (value, { action }) => {
    if (action === "input-change") {
      setValueInputValue(value);
    }
    return value;
  };
  const onOperatorChange = (v) => {
    var _a2, _b2;
    const existingOperator = filter.operator;
    const newOperator = v.value;
    const update = { operator: newOperator };
    if (isMultiValueOperator(existingOperator) && !isMultiValueOperator(newOperator)) {
      update.value = "";
      update.valueLabels = [""];
      update.values = void 0;
      setUncommittedValue([]);
    } else if (!isMultiValueOperator(existingOperator) && isMultiValueOperator(newOperator) && filter.value) {
      update.values = [filter.value];
      setUncommittedValue([
        {
          value: filter.value,
          label: (_b2 = (_a2 = filter.valueLabels) == null ? void 0 : _a2[0]) != null ? _b2 : filter.value
        }
      ]);
    }
    model._updateFilter(filter, update);
  };
  const filteredValueOptions = useMemo(
    () => handleOptionGroups(optionSearcher(valueInputValue)),
    [optionSearcher, valueInputValue]
  );
  const multiValueProps = {
    isMulti: true,
    value: uncommittedValue,
    components: {
      Option: OptionWithCheckbox
    },
    hideSelectedOptions: false,
    closeMenuOnSelect: false,
    openMenuOnFocus: false,
    onChange: (v) => {
      setUncommittedValue(v);
      if (v.some((value) => value.__isNew__)) {
        setValueInputValue("");
      }
    },
    onBlur: () => {
      var _a2, _b2;
      model._updateFilter(filter, {
        value: (_b2 = (_a2 = uncommittedValue[0]) == null ? void 0 : _a2.value) != null ? _b2 : "",
        // TODO remove expect-error when we're on the latest version of @grafana/data
        values: uncommittedValue.map((option) => option.value),
        valueLabels: uncommittedValue.map((option) => option.label)
      });
    }
  };
  const operatorDefinition = OPERATORS.find((op) => filter.operator === op.value);
  const valueSelect = /* @__PURE__ */ React.createElement(
    Select,
    {
      virtualized: true,
      allowCustomValue: (_b = model.state.allowCustomValue) != null ? _b : true,
      createOptionPosition: (operatorDefinition == null ? void 0 : operatorDefinition.isRegex) ? "first" : "last",
      isValidNewOption: (inputValue) => inputValue.trim().length > 0,
      allowCreateWhileLoading: true,
      formatCreateLabel: (inputValue) => `Use custom value: ${inputValue}`,
      disabled: model.state.readOnly,
      className: cx(styles.value, isValuesOpen ? styles.widthWhenOpen : void 0),
      width: "auto",
      value: valueValue,
      filterOption: filterNoOp$1,
      placeholder: t(
        "grafana-scenes.variables.ad-hoc-filter-renderer.value-select.placeholder-select-value",
        "Select value"
      ),
      options: filteredValueOptions,
      inputValue: valueInputValue,
      onInputChange: onValueInputChange,
      onChange: (v) => {
        if (onAddCustomValue && v.__isNew__) {
          model._updateFilter(filter, onAddCustomValue(v, filter));
        } else {
          model._updateFilter(filter, {
            value: v.value,
            valueLabels: v.label ? [v.label] : [v.value]
          });
        }
        if (valueHasCustomValue !== v.__isNew__) {
          setValueHasCustomValue(v.__isNew__);
        }
      },
      isOpen: isValuesOpen && !isValuesLoading,
      isLoading: isValuesLoading,
      openMenuOnFocus: true,
      onOpenMenu: async () => {
        var _a2;
        setIsValuesLoading(true);
        setIsValuesOpen(true);
        const values2 = await model._getValuesFor(filter);
        setIsValuesLoading(false);
        setValues(values2);
        if (valueHasCustomValue) {
          setValueInputValue((_a2 = valueValue == null ? void 0 : valueValue.label) != null ? _a2 : "");
        }
      },
      onCloseMenu: () => {
        setIsValuesOpen(false);
        setValueInputValue("");
      },
      ...isMultiValue && multiValueProps
    }
  );
  const keySelect = /* @__PURE__ */ React.createElement(
    Select,
    {
      key: `${isValuesLoading ? "loading" : "loaded"}`,
      disabled: model.state.readOnly,
      className: cx(styles.key, isKeysOpen ? styles.widthWhenOpen : void 0),
      width: "auto",
      allowCustomValue: (_c = model.state.allowCustomValue) != null ? _c : true,
      createOptionPosition: (operatorDefinition == null ? void 0 : operatorDefinition.isRegex) ? "first" : "last",
      value: keyValue,
      placeholder: t(
        "grafana-scenes.variables.ad-hoc-filter-renderer.key-select.placeholder-select-label",
        "Select label"
      ),
      options: handleOptionGroups(keys),
      onChange: (v) => {
        model._updateFilter(filter, {
          key: v.value,
          keyLabel: v.label,
          // clear value if key has changed
          value: "",
          valueLabels: [""],
          values: void 0
        });
        setUncommittedValue([]);
      },
      autoFocus: filter.key === "",
      isOpen: isKeysOpen && !isKeysLoading,
      isLoading: isKeysLoading,
      onOpenMenu: async () => {
        setIsKeysOpen(true);
        setIsKeysLoading(true);
        const keys2 = await model._getKeys(filter.key);
        setIsKeysLoading(false);
        setKeys(keys2);
      },
      onCloseMenu: () => {
        setIsKeysOpen(false);
      },
      onBlur: () => {
        if (filter.key === "") {
          model._removeFilter(filter);
        }
      },
      openMenuOnFocus: false
    }
  );
  const operatorSelect = /* @__PURE__ */ React.createElement(
    Select,
    {
      className: cx(styles.operator, {
        [styles.widthWhenOpen]: isOperatorOpen
      }),
      value: filter.operator,
      disabled: model.state.readOnly,
      options: model._getOperators(),
      onChange: onOperatorChange,
      onOpenMenu: () => {
        setIsOperatorOpen(true);
      },
      onCloseMenu: () => {
        setIsOperatorOpen(false);
      }
    }
  );
  if (model.state.layout === "vertical") {
    if (filter.key) {
      const label = /* @__PURE__ */ React.createElement(ControlsLabel, { layout: "vertical", label: (_d = filter.key) != null ? _d : "", onRemove: () => model._removeFilter(filter) });
      return /* @__PURE__ */ React.createElement(Field, { label, "data-testid": `AdHocFilter-${filter.key}`, className: styles.field }, /* @__PURE__ */ React.createElement("div", { className: styles.wrapper }, operatorSelect, valueSelect));
    } else {
      return /* @__PURE__ */ React.createElement(
        Field,
        {
          label: t("grafana-scenes.variables.ad-hoc-filter-renderer.label-select-label", "Select label"),
          "data-testid": `AdHocFilter-${filter.key}`,
          className: styles.field
        },
        keySelect
      );
    }
  }
  return /* @__PURE__ */ React.createElement("div", { className: styles.wrapper, "data-testid": `AdHocFilter-${filter.key}` }, keySelect, operatorSelect, valueSelect, /* @__PURE__ */ React.createElement(
    Button,
    {
      variant: "secondary",
      "aria-label": t("grafana-scenes.variables.ad-hoc-filter-renderer.aria-label-remove-filter", "Remove filter"),
      title: t("grafana-scenes.variables.ad-hoc-filter-renderer.title-remove-filter", "Remove filter"),
      className: styles.removeButton,
      icon: "times",
      "data-testid": `AdHocFilter-remove-${(_e = filter.key) != null ? _e : ""}`,
      onClick: () => model._removeFilter(filter)
    }
  ));
}
const getStyles$k = (theme) => ({
  field: css({
    marginBottom: 0
  }),
  wrapper: css({
    display: "flex",
    "&:first-child": {
      "> :first-child": {
        borderBottomLeftRadius: 0,
        borderTopLeftRadius: 0
      }
    },
    "> *": {
      "&:not(:first-child)": {
        // Negative margin hides the double-border on adjacent selects
        marginLeft: -1
      },
      "&:first-child": {
        borderTopRightRadius: 0,
        borderBottomRightRadius: 0
      },
      "&:last-child": {
        borderTopLeftRadius: 0,
        borderBottomLeftRadius: 0
      },
      "&:not(:first-child):not(:last-child)": {
        borderRadius: 0
      },
      // Fix focus state zIndex issues
      position: "relative",
      zIndex: 0,
      // Adjacent borders are overlapping, so raise children up when hovering etc
      // so all that child's borders are visible.
      "&:hover": {
        zIndex: 1
      },
      "&:focus-within": {
        zIndex: 2
      }
    }
  }),
  widthWhenOpen: css({
    minWidth: theme.spacing(16)
  }),
  value: css({
    flexBasis: "content",
    flexShrink: 1,
    minWidth: "90px"
  }),
  key: css({
    flexBasis: "content",
    minWidth: "90px",
    flexShrink: 1
  }),
  operator: css({
    flexShrink: 0,
    flexBasis: "content"
  }),
  removeButton: css({
    paddingLeft: theme.spacing(3 / 2),
    paddingRight: theme.spacing(3 / 2),
    borderLeft: "none",
    width: theme.spacing(3),
    marginRight: theme.spacing(1),
    boxSizing: "border-box",
    // To not have button background and last select border intersect
    position: "relative",
    left: "1px"
  })
});

export { AdHocFilterRenderer };
//# sourceMappingURL=AdHocFilterRenderer.js.map
