import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
import { css } from '@emotion/css';
import { useMemo, useCallback } from 'react';
import { FixedSizeList } from 'react-window';
import { getValueFormat, formattedValueToString } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { Trans } from '@grafana/i18n';
import { useStyles2, useTheme2 } from '../../../../themes/ThemeContext.mjs';
import { Checkbox } from '../../../Forms/Checkbox.mjs';
import { Label } from '../../../Forms/Label.mjs';
import { Stack } from '../../../Layout/Stack/Stack.mjs';
import { operatorSelectableValues } from './FilterPopup.mjs';

"use strict";
const ITEM_HEIGHT = 28;
const MIN_HEIGHT = ITEM_HEIGHT * 5;
const REGEX_OPERATOR = operatorSelectableValues["Contains"];
const XPR_OPERATOR = operatorSelectableValues["Expression"];
const comparableValue = (value) => {
  value = value.trim().replace(/\\/g, "");
  if (/^(\d{4}-\d{2}-\d{2}|\d{4}\/\d{2}\/\d{2})/.test(value)) {
    const date = new Date(value);
    if (!isNaN(date.getTime())) {
      const fmt = getValueFormat("dateTimeAsIso");
      return formattedValueToString(fmt(date.getTime()));
    }
  }
  const num = parseFloat(value);
  if (!isNaN(num)) {
    return num;
  }
  const lvalue = value.toLowerCase();
  if (lvalue === "true" || lvalue === "false") {
    return lvalue === "true";
  }
  return value;
};
const FilterList = ({ options, values, caseSensitive, onChange, searchFilter, operator }) => {
  const regex = useMemo(() => new RegExp(searchFilter, caseSensitive ? void 0 : "i"), [searchFilter, caseSensitive]);
  const items = useMemo(
    () => options.filter((option) => {
      if (!searchFilter || operator.value === REGEX_OPERATOR.value) {
        if (option.label === void 0) {
          return false;
        }
        return regex.test(option.label);
      } else if (operator.value === XPR_OPERATOR.value) {
        if (option.value === void 0) {
          return false;
        }
        try {
          const xpr = searchFilter.replace(/\\/g, "");
          const fnc = new Function("$", `'use strict'; return ${xpr};`);
          const val = comparableValue(option.value);
          return fnc(val);
        } catch (_) {
        }
        return false;
      } else {
        if (option.value === void 0) {
          return false;
        }
        const value1 = comparableValue(option.value);
        const value2 = comparableValue(searchFilter);
        switch (operator.value) {
          case "=":
            return value1 === value2;
          case "!=":
            return value1 !== value2;
          case ">":
            return value1 > value2;
          case ">=":
            return value1 >= value2;
          case "<":
            return value1 < value2;
          case "<=":
            return value1 <= value2;
        }
        return false;
      }
    }),
    [options, regex, operator, searchFilter]
  );
  const selectedItems = useMemo(() => items.filter((item) => values.includes(item)), [items, values]);
  const selectCheckValue = useMemo(() => items.length === selectedItems.length, [items, selectedItems]);
  const selectCheckIndeterminate = useMemo(
    () => selectedItems.length > 0 && items.length > selectedItems.length,
    [items, selectedItems]
  );
  const selectCheckLabel = useMemo(
    () => selectedItems.length ? `${selectedItems.length} selected` : `Select all`,
    [selectedItems]
  );
  const selectCheckDescription = useMemo(
    () => items.length !== selectedItems.length ? "Add all displayed values to the filter" : "Remove all displayed values from the filter",
    [items, selectedItems]
  );
  const styles = useStyles2(getStyles);
  const theme = useTheme2();
  const gutter = theme.spacing.gridSize;
  const height = useMemo(() => Math.min(items.length * ITEM_HEIGHT, MIN_HEIGHT) + gutter, [gutter, items.length]);
  const onCheckedChanged = useCallback(
    (option) => (event) => {
      const newValues = event.currentTarget.checked ? values.concat(option) : values.filter((c) => c.value !== option.value);
      onChange(newValues);
    },
    [onChange, values]
  );
  const onSelectChanged = useCallback(() => {
    if (items.length === selectedItems.length) {
      const newValues = values.filter((item) => !items.includes(item));
      onChange(newValues);
    } else {
      const newValues = [.../* @__PURE__ */ new Set([...values, ...items])];
      onChange(newValues);
    }
  }, [onChange, values, items, selectedItems]);
  return /* @__PURE__ */ jsx(Stack, { direction: "column", children: items.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
    /* @__PURE__ */ jsx(
      FixedSizeList,
      {
        height,
        itemCount: items.length,
        itemSize: ITEM_HEIGHT,
        itemData: { items, values: selectedItems, onCheckedChanged, className: styles.filterListRow },
        width: "100%",
        className: styles.filterList,
        children: ItemRenderer
      }
    ),
    /* @__PURE__ */ jsx(
      "div",
      {
        className: styles.filterListRow,
        "data-testid": selectors.components.Panels.Visualization.TableNG.Filters.SelectAll,
        children: /* @__PURE__ */ jsx(
          Checkbox,
          {
            value: selectCheckValue,
            indeterminate: selectCheckIndeterminate,
            label: selectCheckLabel,
            description: selectCheckDescription,
            onChange: onSelectChanged
          }
        )
      }
    )
  ] }) : /* @__PURE__ */ jsx(Label, { className: styles.noValuesLabel, children: /* @__PURE__ */ jsx(Trans, { i18nKey: "grafana-ui.table.no-values-label", children: "No values" }) }) });
};
function ItemRenderer({ index, style, data: { onCheckedChanged, items, values, className } }) {
  const option = items[index];
  const { value, label } = option;
  const isChecked = values.find((s) => s.value === value) !== void 0;
  return /* @__PURE__ */ jsx("div", { className, style, title: label, children: /* @__PURE__ */ jsx(Checkbox, { value: isChecked, label, onChange: onCheckedChanged(option) }) });
}
const getStyles = (theme) => ({
  filterList: css({
    label: "filterList",
    backgroundColor: theme.components.input.background,
    border: `1px solid ${theme.colors.border.medium}`,
    borderRadius: theme.shape.radius.default
  }),
  filterListRow: css({
    label: "filterListRow",
    cursor: "pointer",
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis",
    padding: theme.spacing(0.5),
    ":hover": {
      backgroundColor: theme.colors.action.hover
    }
  }),
  selectDivider: css({
    label: "selectDivider",
    width: "100%",
    borderTop: `1px solid ${theme.colors.border.medium}`,
    padding: theme.spacing(0.5, 2)
  }),
  noValuesLabel: css({
    paddingTop: theme.spacing(1)
  })
});

export { FilterList, REGEX_OPERATOR };
//# sourceMappingURL=FilterList.mjs.map
