import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
import { t } from 'i18next';
import { isArray, negate } from 'lodash';
import * as React from 'react';
import { useRef, useState, useEffect, useCallback } from 'react';
import ReactSelect from 'react-select';
import ReactAsyncSelect from 'react-select/async';
import AsyncCreatable from 'react-select/async-creatable';
import Creatable from 'react-select/creatable';
import { toOption } from '@grafana/data';
import { useTheme2 } from '../../themes/ThemeContext.js';
import 'micro-memoize';
import '@emotion/react';
import 'tinycolor2';
import '../../utils/skeleton.js';
import { Icon } from '../Icon/Icon.js';
import { Spinner } from '../Spinner/Spinner.js';
import { CustomInput } from './CustomInput.js';
import { DropdownIndicator } from './DropdownIndicator.js';
import { IndicatorsContainer } from './IndicatorsContainer.js';
import { InputControl } from './InputControl.js';
import { MultiValueContainer, MultiValueRemove } from './MultiValue.js';
import { SelectContainer } from './SelectContainer.js';
import { SelectMenuOptions, VirtualizedSelectMenu, SelectMenu } from './SelectMenu.js';
import { SelectOptionGroup } from './SelectOptionGroup.js';
import { SelectOptionGroupHeader } from './SelectOptionGroupHeader.js';
import { SingleValue } from './SingleValue.js';
import { ValueContainer } from './ValueContainer.js';
import { getSelectStyles } from './getSelectStyles.js';
import { useCustomSelectStyles } from './resetSelectStyles.js';
import { ToggleAllState } from './types.js';
import { findSelectedValue, cleanValue, omitDescriptions } from './utils.js';

const CustomControl = (props) => {
  const {
    children,
    innerProps,
    selectProps: { menuIsOpen, onMenuClose, onMenuOpen },
    isFocused,
    isMulti,
    getValue,
    innerRef
  } = props;
  const selectProps = props.selectProps;
  if (selectProps.renderControl) {
    return React.createElement(selectProps.renderControl, {
      isOpen: menuIsOpen,
      value: isMulti ? getValue() : getValue()[0],
      ref: innerRef,
      onClick: menuIsOpen ? onMenuClose : onMenuOpen,
      onBlur: onMenuClose,
      disabled: !!selectProps.disabled,
      invalid: !!selectProps.invalid
    });
  }
  return /* @__PURE__ */ jsx(
    InputControl,
    {
      ref: innerRef,
      innerProps,
      prefix: selectProps.prefix,
      focused: isFocused,
      invalid: !!selectProps.invalid,
      disabled: !!selectProps.disabled,
      children
    }
  );
};
function determineToggleAllState(selectedValue, options) {
  if (options.length === selectedValue.length) {
    return ToggleAllState.allSelected;
  } else if (selectedValue.length === 0) {
    return ToggleAllState.noneSelected;
  } else {
    return ToggleAllState.indeterminate;
  }
}
function SelectBase({
  allowCustomValue = false,
  allowCreateWhileLoading = false,
  "aria-label": ariaLabel,
  "data-testid": dataTestid,
  autoFocus = false,
  backspaceRemovesValue = true,
  blurInputOnSelect,
  cacheOptions,
  className,
  closeMenuOnSelect = true,
  components,
  createOptionPosition = "last",
  defaultOptions,
  defaultValue,
  disabled = false,
  filterOption,
  formatCreateLabel,
  getOptionLabel,
  getOptionValue,
  inputValue,
  invalid,
  isClearable = false,
  id,
  isLoading = false,
  isMulti = false,
  inputId,
  isOpen,
  isOptionDisabled,
  isSearchable = true,
  loadOptions,
  loadingMessage = "Loading options...",
  maxMenuHeight = 300,
  minMenuHeight,
  maxVisibleValues,
  menuPlacement = "auto",
  menuPosition,
  menuShouldPortal = true,
  noOptionsMessage = t("grafana-ui.select.no-options-label", "No options found"),
  onBlur,
  onChange,
  onCloseMenu,
  onCreateOption,
  onInputChange,
  onKeyDown,
  onMenuScrollToBottom,
  onMenuScrollToTop,
  onOpenMenu,
  onFocus,
  toggleAllOptions,
  openMenuOnFocus = false,
  options = [],
  placeholder = t("grafana-ui.select.placeholder", "Choose"),
  prefix,
  renderControl,
  showAllSelectedWhenOpen = true,
  tabSelectsValue = true,
  value,
  virtualized = false,
  noMultiValueWrap,
  width,
  isValidNewOption,
  formatOptionLabel,
  hideSelectedOptions,
  ...rest
}) {
  const theme = useTheme2();
  const styles = getSelectStyles(theme);
  const reactSelectRef = useRef(null);
  const [closeToBottom, setCloseToBottom] = useState(false);
  const selectStyles = useCustomSelectStyles(theme, width);
  const [hasInputValue, setHasInputValue] = useState(!!inputValue);
  useEffect(() => {
    if (loadOptions && isOpen && reactSelectRef.current && reactSelectRef.current.controlRef && menuPlacement === "auto") {
      const distance = window.innerHeight - reactSelectRef.current.controlRef.getBoundingClientRect().bottom;
      setCloseToBottom(distance < maxMenuHeight);
    }
  }, [maxMenuHeight, menuPlacement, loadOptions, isOpen]);
  const onChangeWithEmpty = useCallback(
    (value2, action) => {
      if (isMulti && (value2 === void 0 || value2 === null)) {
        return onChange([], action);
      }
      onChange(value2, action);
    },
    [isMulti, onChange]
  );
  let ReactSelectComponent = ReactSelect;
  const creatableProps = {};
  let asyncSelectProps = {};
  let selectedValue;
  if (isMulti && loadOptions) {
    selectedValue = value;
  } else {
    if (isMulti && value && Array.isArray(value) && !loadOptions) {
      selectedValue = value.map((v) => {
        var _a;
        const selectableValue = findSelectedValue((_a = v.value) != null ? _a : v, options);
        if (selectableValue) {
          return selectableValue;
        }
        return typeof v === "string" ? toOption(v) : v;
      });
    } else if (loadOptions) {
      const hasValue = defaultValue || value;
      selectedValue = hasValue ? [hasValue] : [];
    } else {
      selectedValue = cleanValue(value, options);
    }
  }
  const commonSelectProps = {
    "aria-label": ariaLabel,
    "data-testid": dataTestid,
    autoFocus,
    backspaceRemovesValue,
    blurInputOnSelect,
    captureMenuScroll: onMenuScrollToBottom || onMenuScrollToTop,
    closeMenuOnSelect,
    // We don't want to close if we're actually scrolling the menu
    // So only close if none of the parents are the select menu itself
    defaultValue,
    // Also passing disabled, as this is the new Select API, and I want to use this prop instead of react-select's one
    disabled,
    // react-select always tries to filter the options even at first menu open, which is a problem for performance
    // in large lists. So we set it to not try to filter the options if there is no input value.
    filterOption: hasInputValue ? filterOption : null,
    getOptionLabel,
    getOptionValue,
    hideSelectedOptions,
    inputValue,
    invalid,
    isClearable,
    id,
    // Passing isDisabled as react-select accepts this prop
    isDisabled: disabled,
    isLoading,
    isMulti,
    inputId,
    isOptionDisabled,
    isSearchable,
    maxMenuHeight,
    minMenuHeight,
    maxVisibleValues,
    menuIsOpen: isOpen,
    menuPlacement: menuPlacement === "auto" && closeToBottom ? "top" : menuPlacement,
    menuPosition,
    menuShouldBlockScroll: true,
    menuPortalTarget: menuShouldPortal && typeof document !== "undefined" ? document.body : void 0,
    menuShouldScrollIntoView: false,
    onBlur,
    onChange: onChangeWithEmpty,
    onInputChange: (val, actionMeta) => {
      var _a;
      const newValue = (_a = onInputChange == null ? void 0 : onInputChange(val, actionMeta)) != null ? _a : val;
      const newHasValue = !!newValue;
      if (newHasValue !== hasInputValue) {
        setHasInputValue(newHasValue);
      }
      return newValue;
    },
    onKeyDown,
    onMenuClose: onCloseMenu,
    onMenuOpen: onOpenMenu,
    onMenuScrollToBottom,
    onMenuScrollToTop,
    onFocus,
    formatOptionLabel,
    openMenuOnFocus,
    options: virtualized ? omitDescriptions(options) : options,
    placeholder,
    prefix,
    renderControl,
    showAllSelectedWhenOpen,
    tabSelectsValue,
    value: isMulti ? selectedValue : selectedValue == null ? void 0 : selectedValue[0],
    noMultiValueWrap
  };
  if (allowCustomValue) {
    ReactSelectComponent = Creatable;
    creatableProps.allowCreateWhileLoading = allowCreateWhileLoading;
    creatableProps.formatCreateLabel = formatCreateLabel != null ? formatCreateLabel : defaultFormatCreateLabel;
    creatableProps.onCreateOption = onCreateOption;
    creatableProps.createOptionPosition = createOptionPosition;
    creatableProps.isValidNewOption = isValidNewOption;
  }
  if (loadOptions) {
    ReactSelectComponent = allowCustomValue ? AsyncCreatable : ReactAsyncSelect;
    asyncSelectProps = {
      loadOptions,
      cacheOptions,
      defaultOptions
    };
  }
  const SelectMenuComponent = virtualized ? VirtualizedSelectMenu : SelectMenu;
  let toggleAllState = ToggleAllState.noneSelected;
  if ((toggleAllOptions == null ? void 0 : toggleAllOptions.enabled) && isArray(selectedValue)) {
    if (toggleAllOptions == null ? void 0 : toggleAllOptions.determineToggleAllState) {
      toggleAllState = toggleAllOptions.determineToggleAllState(selectedValue, options);
    } else {
      toggleAllState = determineToggleAllState(selectedValue, options);
    }
  }
  const toggleAll = useCallback(() => {
    let toSelect = toggleAllState === ToggleAllState.noneSelected ? options : [];
    if (toggleAllOptions == null ? void 0 : toggleAllOptions.optionsFilter) {
      toSelect = toggleAllState === ToggleAllState.noneSelected ? options.filter(toggleAllOptions.optionsFilter) : options.filter(negate(toggleAllOptions.optionsFilter));
    }
    onChange(toSelect, {
      action: "select-option",
      option: {}
    });
  }, [options, toggleAllOptions, onChange, toggleAllState]);
  return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(
    ReactSelectComponent,
    {
      ref: reactSelectRef,
      components: {
        MenuList: SelectMenuComponent,
        Group: SelectOptionGroup,
        GroupHeading: SelectOptionGroupHeader,
        ValueContainer,
        IndicatorsContainer: CustomIndicatorsContainer,
        IndicatorSeparator,
        Control: CustomControl,
        Option: SelectMenuOptions,
        ClearIndicator(props) {
          const { clearValue } = props;
          return /* @__PURE__ */ jsx(
            Icon,
            {
              name: "times",
              role: "button",
              "aria-label": "select-clear-value",
              className: styles.singleValueRemove,
              onMouseDown: (e) => {
                e.preventDefault();
                e.stopPropagation();
                clearValue();
              }
            }
          );
        },
        LoadingIndicator() {
          return /* @__PURE__ */ jsx(Spinner, { inline: true });
        },
        LoadingMessage() {
          return /* @__PURE__ */ jsx("div", { className: styles.loadingMessage, children: loadingMessage });
        },
        NoOptionsMessage() {
          return /* @__PURE__ */ jsx("div", { className: styles.loadingMessage, "aria-label": "No options provided", children: noOptionsMessage });
        },
        DropdownIndicator,
        SingleValue(props) {
          return /* @__PURE__ */ jsx(SingleValue, { ...props, isDisabled: disabled });
        },
        SelectContainer,
        MultiValueContainer,
        MultiValueRemove: !disabled ? MultiValueRemove : () => null,
        Input: CustomInput,
        ...components
      },
      toggleAllOptions: (toggleAllOptions == null ? void 0 : toggleAllOptions.enabled) && {
        state: toggleAllState,
        selectAllClicked: toggleAll,
        selectedCount: isArray(selectedValue) ? selectedValue.length : void 0
      },
      styles: selectStyles,
      className,
      ...commonSelectProps,
      ...creatableProps,
      ...asyncSelectProps,
      ...rest
    }
  ) });
}
function defaultFormatCreateLabel(input) {
  return /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center" }, children: [
    /* @__PURE__ */ jsx("div", { children: input }),
    /* @__PURE__ */ jsx("div", { style: { flexGrow: 1 } }),
    /* @__PURE__ */ jsx("div", { className: "muted small", style: { display: "flex", gap: "8px", alignItems: "center" }, children: "Hit enter to add" })
  ] });
}
function CustomIndicatorsContainer(props) {
  const { showAllSelectedWhenOpen, maxVisibleValues, menuIsOpen } = props.selectProps;
  const value = props.getValue();
  if (maxVisibleValues !== void 0 && Array.isArray(props.children)) {
    const selectedValuesCount = value.length;
    if (selectedValuesCount > maxVisibleValues && !(showAllSelectedWhenOpen && menuIsOpen)) {
      const indicatorChildren = [...props.children];
      indicatorChildren.splice(
        -1,
        0,
        /* @__PURE__ */ jsxs("span", { id: "excess-values", children: [
          "(+",
          selectedValuesCount - maxVisibleValues,
          ")"
        ] }, "excess-values")
      );
      return /* @__PURE__ */ jsx(IndicatorsContainer, { ...props, children: indicatorChildren });
    }
  }
  return /* @__PURE__ */ jsx(IndicatorsContainer, { ...props });
}
function IndicatorSeparator() {
  return /* @__PURE__ */ jsx(Fragment, {});
}

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