// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

import { useState, useRef, Children, isValidElement } from 'react';
import classNames from 'classnames';
import { CLS_PREFIX } from '../../constants';
import { safeInvoke, EventEmitter } from '../utils';
import Input from '../Input';
import Icon from '../Icon';
import ComboBoxDropdown, { findNextSafeIndex } from '../ComboBoxDropdown';
import ComboBoxOption from './ComboBoxOption';
import { jsx as _jsx } from "react/jsx-runtime";
const collect = function (children) {
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  Children.forEach(children, child => {
    if ( /*#__PURE__*/isValidElement(child) && child.type === ComboBoxOption) {
      // eslint-disable-next-line prefer-const
      let {
        disabled,
        children: value,
        children,
        ...props
      } = child.props;
      if (typeof value !== 'string') {
        throw new Error('The value can only be a number or a string.');
      }
      const option = {
        value: String(value),
        children,
        disabled: Boolean(disabled),
        props
      };
      options.push(option);
    }
  });
  return {
    options
  };
};
/**
 * `ComboBox` component is a combination of [Select](#!/Select) and [Input](#!/Input)
 *  which allows to either enter a value directly into the field or choose from a list of existing options.
 * @since 2.6.0
 */
const ComboBox = _ref => {
  let {
    baseClassName = `${CLS_PREFIX}combobox`,
    className,
    value = '',
    onChange,
    disabled = false,
    size,
    textAlign,
    placeholder,
    children,
    ...props
  } = _ref;
  const [opened, setOpened] = useState(false);
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
  const inputRef = useRef(null);
  const controlRef = useRef(null);
  const emitterRef = useRef(new EventEmitter());
  const {
    options
  } = collect(children);
  const handleClose = () => {
    setOpened(false);
    setHighlightedIndex(-1);
  };
  const handleToggle = () => {
    if (opened) {
      handleClose();
    } else {
      setOpened(true);
      if (inputRef.current) {
        inputRef.current.focus();
      }
    }
  };
  const handleChange = nextValue => safeInvoke(onChange, nextValue);
  const handleInputChange = e => handleChange(e.target.value);
  const handleSelect = nextValue => {
    handleChange(nextValue);
    handleClose();
  };
  const moveHighlightedIndex = diff => {
    if (!opened) {
      setOpened(true);
    }
    const nextIndex = findNextSafeIndex(highlightedIndex, diff, options);
    if (nextIndex !== -1) {
      setHighlightedIndex(nextIndex);
      emitterRef.current.emit('focus', nextIndex);
    }
  };
  const confirmHighlightedIndex = index => {
    if (!opened && index === undefined) {
      return;
    }
    const option = options[index === undefined ? highlightedIndex : index];
    if (!option) {
      return;
    }
    if (option.disabled) {
      return;
    }
    const nextValue = option.value;
    safeInvoke(onChange, nextValue);
  };
  const handleHighlightedIndexChange = index => {
    setHighlightedIndex(index);
  };
  const handleKeyDown = e => {
    switch (e.key) {
      case 'ArrowUp':
        e.preventDefault();
        setOpened(true);
        moveHighlightedIndex(-1);
        break;
      case 'ArrowDown':
        e.preventDefault();
        setOpened(true);
        moveHighlightedIndex(1);
        break;
      case 'Enter':
        if (opened) {
          e.preventDefault();
          confirmHighlightedIndex(highlightedIndex);
          handleClose();
        }
        break;
      case 'Escape':
        e.preventDefault();
        handleClose();
        break;
    }
  };
  const button = /*#__PURE__*/_jsx("button", {
    className: `${baseClassName}__dropdown-button`,
    onClick: handleToggle,
    onMouseDown: e => e.preventDefault(),
    disabled: disabled,
    type: "button",
    tabIndex: -1,
    children: /*#__PURE__*/_jsx(Icon, {
      name: "chevron-down"
    })
  });
  const control = /*#__PURE__*/_jsx(Input, {
    className: classNames(`${baseClassName}__input`, {
      [`${baseClassName}__input--disabled`]: disabled
    }),
    value: value,
    suffix: button,
    disabled: disabled,
    onChange: handleInputChange,
    onKeyDown: handleKeyDown,
    size: "fill",
    textAlign: textAlign,
    placeholder: placeholder,
    innerRef: el => {
      inputRef.current = el;
    },
    rootProps: {
      ref: controlRef
    }
  });
  return /*#__PURE__*/_jsx(ComboBoxDropdown, {
    className: classNames(baseClassName, className, {
      [`${baseClassName}--size-${size}`]: size
    }),
    control: control,
    controlRef: controlRef,
    opened: opened && !disabled,
    disabled: disabled,
    groups: [{
      options
    }],
    options: options,
    onSelect: handleSelect,
    highlightedIndex: highlightedIndex,
    onHighlightedIndexChange: handleHighlightedIndexChange,
    onClose: handleClose,
    value: value,
    emitter: emitterRef.current,
    ...props
  });
};
const withDefaultValue = Component => {
  const Wrapper = props => {
    const {
      defaultValue,
      onChange
    } = props;
    const [value, setValue] = useState(defaultValue);
    let propOverrides;
    if (props.value === undefined) {
      propOverrides = {
        value,
        onChange: nextValue => {
          setValue(nextValue);
          safeInvoke(onChange, nextValue);
        }
      };
    }
    return /*#__PURE__*/_jsx(Component, {
      ...props,
      ...propOverrides
    });
  };
  Wrapper.displayName = `withDefaultValue(${Component.name})`;
  return Wrapper;
};
export default withDefaultValue(ComboBox);