import PropTypes from 'prop-types';
import getColor from "../../../utils/colors/getColor.js";
import { AutoLayout } from "../../layout/index.js";
import cx from "../../../utils/css/cx.js";
import getEdgeClasses from "../../../utils/css/getEdgeClasses.js";
import normalizeStatefulColorSet from "../../../utils/colors/normalizeStatefulColorSet.js";
import getShadowClasses from "../../../utils/css/getShadowClasses.js";
import customizable from "../../../utils/css/customizable.js";
import { IconCaretDown, IconCaretUp, IconX } from "../../icons/index.js";
import { IfActive } from "../../application/index.js";
import classes from './styles.module.scss';
import Input from './Input';
import Results from './Results';
import useSearchEvents from './useSearchEvents';
import Button from '../Button';
const cls = cx.merge(classes, {
  customizable: ['SearchInput', 'SearchInput__label']
});

/**
 * A search input that takes an array of options and returns a key from
 * the selected object in the array.
 *
 * The component has been built to handle keyboard events as specificed in the ARIA authoring practices [combobox guide](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
 */
const SearchInput = function SearchInput(props) {
  const {
    searchOptions,
    searchKey,
    value,
    setValue,
    search: customSearch,
    placeholder,
    label,
    ariaResultsLabel,
    popupBg,
    focusFg,
    focusBg,
    autoLayout,
    edge,
    border,
    shadow,
    buttonProps
  } = props;
  const {
    searchQuery,
    setSearchQuery,
    searchResults,
    closeResults,
    activeDescendent,
    updateActiveDescendent,
    updateUserSelection,
    inputRef,
    resultsId,
    inputId,
    showList,
    setShowList
  } = useSearchEvents({
    searchOptions,
    searchKey,
    customSearch,
    setValue,
    value
  });
  const resultsVisible = showList || searchQuery;
  const states = ['default', 'hover', 'focus', 'disabled'];
  const edgeClasses = getEdgeClasses(edge);
  const shadowClasses = getShadowClasses(shadow);
  const borders = normalizeStatefulColorSet(border, states);
  const icon = showList ? <IconCaretUp /> : <IconCaretDown />;
  return <div className={cls('container', customizable('SearchInput'))} style={{
    '--SearchInput-popup-bg': getColor(popupBg),
    '--SearchInput-focus-bg': getColor(focusBg),
    '--SearchInput-focus-fg': getColor(focusFg),
    '--SearchInput-border': getColor(borders.default),
    '--SearchInput-border-hover': getColor(borders.hover),
    '--SearchInput-border-focus': getColor(borders.focus),
    '--SearchInput-border-disabled': getColor(borders.focus)
  }}>
      <AutoLayout direction="vertical" gap="2" {...autoLayout}>
        <label className={cls('label', customizable('SearchInput__label'))} htmlFor={inputId}>
          {label}
        </label>
        <div className={cls('controls')}>
          <Input resultsVisible={resultsVisible} resultsId={resultsId} inputId={inputId} placeholder={placeholder} setSearchQuery={setSearchQuery} activeDescendent={activeDescendent} updateActiveDescendent={updateActiveDescendent} closeResults={closeResults} updateUserSelection={updateUserSelection} inputRef={inputRef} setShowList={setShowList} edgeClasses={edgeClasses} shadowClasses={shadowClasses} />
          <Button type="button" onClick={() => setShowList(prev => !prev)} fg="white" bg="warmgray-100" icon={icon} padding="0" title={showList ? 'Open list' : 'Close list'} edge={edge} {...buttonProps} />
          <IfActive active={value}>
            <span className={cls('clear-button')}>
              <Button padding="0" fg="warmgray-60" bg="white" size="small" icon={<IconX />} onClick={() => updateUserSelection(null)} />
            </span>
          </IfActive>
        </div>
        <Results id={resultsId} searchResults={searchResults} resultsVisible={resultsVisible} searchKey={searchKey} activeDescendent={activeDescendent} updateUserSelection={updateUserSelection} ariaResultsLabel={ariaResultsLabel} shadowClasses={shadowClasses} />

      </AutoLayout>

    </div>;
};
SearchInput.defaultProps = {
  value: undefined,
  setValue: undefined,
  placeholder: 'Search',
  searchKey: 'label',
  search: undefined,
  label: 'Search',
  clearLabel: undefined,
  ariaResultsLabel: 'Search results',
  popupBg: undefined,
  focusBg: undefined,
  focusFg: undefined,
  autoLayout: undefined,
  edge: '2',
  border: {
    default: 'warmgray-60',
    hover: 'warmgray-100',
    focus: 'warmgray-100',
    disabled: 'warmgray-10'
  },
  shadow: '000',
  buttonProps: {}
};
SearchInput.propTypes = {
  /**
   * A list of options to search when a user provides an input.
   */
  searchOptions: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
  /**
   * The keyname to use search the objects in the options array
   */
  searchKey: PropTypes.string,
  /**
   * Custom search function
   */
  search: PropTypes.func,
  /**
   * A state variable that will be set with the value the user selects
   */
  value: PropTypes.shape({}),
  /**
   * A state-setting function
   */
  setValue: PropTypes.func,
  /**
   * Placeholder text before a user adds any input
   */
  placeholder: PropTypes.string,
  /**
   * Text label describing what the search does
   */
  label: PropTypes.string,
  /**
   * Label for the button that clears the input. If this label is not
   * provided, the clear button is not rendered.
   */
  clearLabel: PropTypes.string,
  /**
   * Short label describing the results list for screenreader users.
   * For example, a list of states might be labeled "States"
   */
  ariaResultsLabel: PropTypes.string,
  /**
   * Sets the background color of the list popup, which is `white` by default. This
   * prop accepts either a color name provided by this library or a CSS color
   * value.
   */
  popupBg: PropTypes.string,
  /**
   * Sets the background color of the visually focused elements in the popup, which is `warmgray-10` by default. This
   * prop accepts either a color name provided by this library or a CSS color
   * value.
   */
  focusBg: PropTypes.string,
  /**
   * Sets the foreground color of the visually focused elements in the popup, which is `black` by default. This
   * prop accepts either a color name provided by this library or a CSS color
   * value.
   */
  focusFg: PropTypes.string,
  /**
   * An `AutoLayout` configuration to passs to the containing div.
   */
  autoLayout: PropTypes.shape({}),
  /**
   * Set the corner style of the input to one of our standard edge levels. In
   * general, either sharp or round edges should be used consistently within
   * a single project.
   */
  edge: PropTypes.oneOf(['0', '1', '2', '3', '4', '5', '6', '8', 'round', 'sharp', 'max']),
  /**
   * A stateful color set to use for the border color of the input. The
   * supported states are `default`, `hover` and `focus`,  if
   * a string is provided it is considered shorthand for the `default` state
   * color. Each color value can be either the name of a color provided by this
   * library (e.g., `altblack-80`) or a valid CSS color (e.g., `red`,
   * `#f04444`).
   */
  border: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    default: PropTypes.string,
    hover: PropTypes.string,
    focus: PropTypes.string,
    disabled: PropTypes.string
  })]),
  /**
   * The level of shadow that the input and dropdown should have, if any.
   * See documentation on our shadow levels for guidance on which level to use.
   */
  shadow: PropTypes.oneOf(['000', '100', '200', '300', '400']),
  /**
   * Props that get passed down to the `Button` component that conrols the dropdown
   */
  buttonProps: PropTypes.shape({})
};
export default SearchInput;