import _defineProperty from "@babel/runtime/helpers/defineProperty";
// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

import { isRtl } from '../../utils';
import React, { Component, cloneElement, Children, useContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { CLS_PREFIX } from '../../constants';
import ButtonGroup from '../ButtonGroup';
import Input from '../Input';
import Button from '../Button';
import Badge from '../Badge';
import Menu, { MenuItem, MenuSelectableItem } from '../Menu';
import ResponsiveContext from '../ResponsiveContext';
import DistractionFreeModeContext from '../DistractionFreeModeContext';
import { safeInvoke } from '../utils';
import { jsx as _jsx } from "react/jsx-runtime";
import { Fragment as _Fragment } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";
/**
 * `SearchBar` component is used for providing type-as-you-go search.
 * @since 0.0.58
 */
class SearchBar extends Component {
  constructor() {
    super(...arguments);
    _defineProperty(this, "state", {
      focused: false,
      overMenu: false,
      value: this.props.inputProps.value || '',
      highlightedValue: null
    });
    _defineProperty(this, "isFocusScheduled", false);
    _defineProperty(this, "keyboardNavigation", key => {
      const {
        onItemSelect,
        results
      } = this.props;
      const highlightedValue = this.getHighlightedValue();
      if (!results || !onItemSelect) {
        return;
      }
      const res = this.getResults();
      const currentIndex = res.indexOf(highlightedValue);
      let nextIndex;
      if (key === 'ArrowUp') {
        nextIndex = Math.max(currentIndex - 1, 0);
      } else if (key === 'ArrowDown') {
        nextIndex = Math.min(currentIndex + 1, res.length - 1);
      }
      this.setState({
        highlightedValue: currentIndex === -1 ? null : res[nextIndex]
      });
    });
    _defineProperty(this, "handleFocus", () => {
      this.setState({
        focused: true
      });
      this.search && this.search.focus();
    });
    _defineProperty(this, "handleBlur", () => {
      this.setState({
        focused: false
      });
      this.search && this.search.blur();
    });
    _defineProperty(this, "handleMenuMouseOver", () => {
      this.setState({
        overMenu: true
      });
    });
    _defineProperty(this, "handleMenuMouseOut", () => {
      this.setState({
        overMenu: false
      });
    });
    _defineProperty(this, "handleKeyDown", e => {
      const {
        onTyping
      } = this.props;
      const {
        value
      } = e.target;
      if (['Enter', 'Escape', 'ArrowUp', 'ArrowDown'].indexOf(e.key) !== -1) {
        this.checkKeys(e.key);
        return;
      }
      this.setState({
        value
      });
      if (onTyping) {
        onTyping(value, () => this.clearInput());
      }
    });
    _defineProperty(this, "handleSearch", () => {
      const {
        onSearch,
        onTyping
      } = this.props;
      const {
        value
      } = this.state;
      if (onSearch) {
        onSearch(value, () => this.clearInput());
      } else if (onTyping) {
        onTyping(value, () => this.clearInput());
      }
    });
    _defineProperty(this, "handleReset", () => {
      this.clearInput();
      this.handleFocus();
    });
    _defineProperty(this, "handleSelect", value => () => {
      const {
        onItemSelect
      } = this.props;
      this.setState({
        highlightedValue: null
      });
      this.handleBlur();
      if (onItemSelect) {
        onItemSelect(value, () => this.clearInput());
      } else {
        this.clearInput();
      }
    });
    _defineProperty(this, "handleExpand", () => {
      const {
        onExpand,
        distractionFreeMode
      } = this.props;
      this.isFocusScheduled = true;
      safeInvoke(onExpand);
      if (distractionFreeMode) {
        distractionFreeMode.toggle();
      }
    });
    _defineProperty(this, "handleCollapse", () => {
      const {
        onCollapse,
        distractionFreeMode
      } = this.props;
      safeInvoke(onCollapse);
      if (distractionFreeMode) {
        distractionFreeMode.toggle();
      }
    });
  }
  static getDerivedStateFromProps(props, state) {
    const {
      inputProps: {
        value: inputPropsValue
      } = {}
    } = props;
    const {
      prevInputProps: {
        value: prevInputPropsValue
      } = {}
    } = state;
    const nextState = {};
    if (inputPropsValue !== prevInputPropsValue) {
      nextState.value = inputPropsValue;
    }
    nextState.prevInputProps = props.inputProps;
    return nextState;
  }
  componentDidUpdate() {
    if (this.isFocusScheduled) {
      this.handleFocus();
      this.isFocusScheduled = false;
    }
  }
  isResponsive() {
    return this.props.responsive;
  }
  getResults() {
    let innerResults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
    const {
      results
    } = this.props;
    if (!results) {
      return [];
    }
    if (results.type === Menu || innerResults) {
      let res = [];
      const children = innerResults || results.props.children;
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        if (!child) {
          continue;
        }
        if (child instanceof Array) {
          res = res.concat(this.getResults(child));
        } else if (child.type === MenuItem || child.type === MenuSelectableItem) {
          res.push(child.key);
        }
      }
      return res;
    }
    return results.map(item => item.value);
  }
  getHighlightedValue() {
    return this.state.highlightedValue || this.getResults()[0];
  }
  searchAction() {
    const {
      onItemSelect,
      results
    } = this.props;
    const highlightedValue = this.getHighlightedValue();
    if (onItemSelect && results) {
      const res = this.getResults();
      const currentIndex = res.indexOf(highlightedValue);
      if (currentIndex === -1) {
        this.handleSearch();
      } else {
        this.handleSelect(highlightedValue)();
      }
    } else {
      this.handleSearch();
    }
  }
  checkKeys(key) {
    if (key === 'Enter') {
      this.searchAction();
    } else if (key === 'Escape') {
      if (this.state.value) {
        this.handleReset();
      } else {
        this.handleBlur();
        this.handleMenuMouseOut();
      }
    } else if (key === 'ArrowUp' || key === 'ArrowDown') {
      this.keyboardNavigation(key);
    }
  }
  clearInput() {
    this.setState({
      value: ''
    }, this.handleSearch);
  }
  elementsIndexToKeyMapping(elements) {
    let result = [];
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      if (!element) {
        continue;
      }
      if (element instanceof Array) {
        result = result.concat(this.elementsIndexToKeyMapping(element));
      } else {
        result.push(element.key);
      }
    }
    return result;
  }
  renderResults() {
    const {
      baseClassName,
      results
    } = this.props;
    const {
      focused,
      overMenu
    } = this.state;
    const highlightedValue = this.getHighlightedValue();
    if (!results || results.length === 0) {
      return null;
    }
    return /*#__PURE__*/_jsx(Menu, {
      className: classNames(`${baseClassName}__results`, {
        [`${baseClassName}__results--hidden`]: !focused && !overMenu
      }),
      onMouseOver: this.handleMenuMouseOver,
      onMouseOut: this.handleMenuMouseOut,
      children: results.map(item => /*#__PURE__*/_jsx(MenuItem, {
        active: item.value === highlightedValue,
        onClick: this.handleSelect(item.value),
        children: item.title
      }, item.value))
    });
  }
  renderResultsMenu() {
    const {
      baseClassName,
      results,
      onItemSelect
    } = this.props;
    const {
      focused,
      overMenu
    } = this.state;
    const highlightedValue = this.getHighlightedValue();
    if (!results) {
      return null;
    }
    return /*#__PURE__*/cloneElement(results, {
      className: classNames(`${baseClassName}__results`, {
        [`${baseClassName}__results--hidden`]: !focused && !overMenu
      }, results.className),
      onMouseOver: this.handleMenuMouseOver,
      onMouseOut: this.handleMenuMouseOut,
      onItemClick: (item, index) => {
        const indexMap = this.elementsIndexToKeyMapping(results.props.children);
        this.handleSelect(indexMap[index])();
      },
      children: Children.map(results.props.children, child => {
        if (onItemSelect && child && (child.type === MenuItem || child.type === MenuSelectableItem)) {
          return /*#__PURE__*/cloneElement(child, {
            active: child.key === highlightedValue
          });
        }
        return child;
      })
    });
  }
  render() {
    const {
      baseClassName,
      className,
      maxWidth,
      minWidth,
      loading,
      responsive,
      onSearch,
      onTyping,
      onItemSelect,
      collapsable,
      onCollapse,
      onExpand,
      results,
      inputProps,
      distractionFreeMode,
      ...props
    } = this.props;
    const {
      focused,
      value
    } = this.state;
    const isCollapsed = this.isResponsive();
    const distractionFreeModeEnabled = Boolean(distractionFreeMode && distractionFreeMode.enabled);
    return /*#__PURE__*/_jsxs("div", {
      className: classNames(baseClassName, {
        [`${baseClassName}--focused`]: focused
      }, className),
      style: isCollapsed || distractionFreeModeEnabled ? null : {
        maxWidth,
        minWidth
      },
      ...props,
      children: [/*#__PURE__*/_jsx(ButtonGroup, {
        className: `${baseClassName}__group`,
        children: isCollapsed && (collapsable || !distractionFreeModeEnabled) ? /*#__PURE__*/_jsx(Badge, {
          intent: "info",
          hidden: !value,
          children: /*#__PURE__*/_jsx(Button, {
            icon: "search",
            onClick: this.handleExpand
          })
        }) : /*#__PURE__*/_jsx(Input, {
          innerRef: ref => this.search = ref,
          className: `${baseClassName}__input`,
          size: "fill",
          onChange: this.handleKeyDown,
          onFocus: this.handleFocus,
          onBlur: this.handleBlur,
          onKeyDown: this.handleKeyDown,
          ...inputProps,
          value: value,
          prefix: (collapsable && !isCollapsed || distractionFreeModeEnabled) && /*#__PURE__*/_jsx(Button, {
            icon: {
              name: 'chevron-right',
              flipHorizontal: isRtl()
            },
            ghost: true,
            onClick: this.handleCollapse
          }),
          suffix: /*#__PURE__*/_jsxs(_Fragment, {
            children: [value && /*#__PURE__*/_jsx(Button, {
              icon: "remove",
              onClick: this.handleReset,
              ghost: true
            }), /*#__PURE__*/_jsx(Button, {
              icon: "search",
              onClick: this.handleSearch,
              state: loading ? 'loading' : null,
              ghost: true
            })]
          })
        })
      }), results && results.type === Menu ? this.renderResultsMenu() : this.renderResults()]
    });
  }
}
const propTypes = {
  /**
   * @ignore
   */
  className: PropTypes.string,
  /**
   * @ignore
   */
  baseClassName: PropTypes.string,
  /**
   * Maximum width of SearchBar
   * @since 0.1.0
   */
  maxWidth: PropTypes.number,
  /**
   * Minimum width of SearchBar
   * @since 0.1.0
   */
  minWidth: PropTypes.number,
  /**
   * Should disable input and show spinner or not.
   * @since 0.1.0
   */
  loading: PropTypes.bool,
  /**
   * Should collapse input or not. Used for control in independence of context.
   * @since 0.1.0
   */
  responsive: PropTypes.bool,
  /**
   * Callback for pressing 'Enter' key or 'Search' button.
   *
   * arguments:
   * * value - search value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onSearch: PropTypes.func,
  /**
   * Callback for pressing any key in input. Used for a live search.
   *
   * arguments:
   * * value - search value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onTyping: PropTypes.func,
  /**
   * Callback for selecting menu item with mouse click or key pressing.
   *
   * arguments:
   * * value - selected value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onItemSelect: PropTypes.func,
  /**
   * Should render toggle button or not.
   * @since 2.2.0
   */
  collapsable: PropTypes.bool,
  /**
   * Callback for pressing toggle button (in normal mode).
   * @since 2.2.0
   */
  onCollapse: PropTypes.func,
  /**
   * Callback for pressing toggle button (in collapsed mode).
   * @since 2.2.0
   */
  onExpand: PropTypes.func,
  /**
   * Results to display.
   * Could be specified by array of objects with "value" and "title" properties or by Menu component.
   * If Menu component is used then key property of MenuItem will be treated as value.
   * @since 0.1.0
   */
  results: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.string.isRequired,
    title: PropTypes.string.isRequired
  })), PropTypes.element]),
  /**
   * Props of underlying input element.
   * @since 0.4.1
   */
  inputProps: PropTypes.object
};
const defaultProps = {
  className: undefined,
  baseClassName: `${CLS_PREFIX}search-bar`,
  maxWidth: 500,
  minWidth: 270,
  loading: false,
  responsive: undefined,
  onSearch: undefined,
  onTyping: undefined,
  onItemSelect: undefined,
  collapsable: false,
  onCollapse: undefined,
  onExpand: undefined,
  results: undefined,
  inputProps: {}
};
SearchBar.propTypes = {
  ...propTypes,
  distractionFreeMode: PropTypes.shape({
    enabled: PropTypes.bool.isRequired,
    toggle: PropTypes.func.isRequired
  })
};
SearchBar.defaultProps = {
  distractionFreeMode: undefined
};
const SearchBarWrapper = props => {
  const distractionFreeMode = useContext(DistractionFreeModeContext);
  let responsive = useContext(ResponsiveContext);
  responsive = props.responsive === undefined ? responsive || false : Boolean(props.responsive);
  return /*#__PURE__*/_jsx(SearchBar, {
    ...props,
    responsive: responsive,
    distractionFreeMode: distractionFreeMode
  });
};
SearchBarWrapper.displayName = 'SearchBar';
SearchBarWrapper.propTypes = propTypes;
SearchBarWrapper.defaultProps = defaultProps;
export default SearchBarWrapper;