import _styled from "styled-components";
import React, { useCallback, useState, useMemo, useEffect, useRef } from "react";
import { Scrollbars } from "react-custom-scrollbars-2";
import { handleKeyboardMovement } from "./HandleKeyboard";
import { StyledAutocompleteBody, StyledAutocompleteNewItem, StyledAutocompleteScrollShadow } from "./Styles";
import highlightText from "../../hooks/useHighlightText";
import { Option } from "../Select/Option";
import { StyledOption } from "../Select/Option/Styles";
import { OptionGroup } from "../Select/OptionGroup";
export function isOptionGroup(item) {
  return item.options !== undefined;
}
export const Autocomplete = _ref => {
  let {
    type,
    options = [],
    inputEl,
    selected = [],
    emptyValue,
    noResultText,
    renderOption = option => option == null ? void 0 : option.name,
    defaultValue,
    sortDirection = "asc",
    handleChange,
    optionClassName,
    handleEmptyAction,
    disabledInternalSort,
    AutocompleteClassName,
    handleDefaultOptionChange,
    preselectDefaultValue,
    keepSameOptionsOrder = false,
    autoHeightMax = 340,
    clearInputOnSelect,
    mixedOptions = []
  } = _ref;
  const itemRef = useRef(null);
  const listRef = useRef(null);
  const selectedOptions = useMemo(() => {
    if (Array.isArray(selected)) {
      return selected;
    }
    return [selected];
  }, [selected]);
  const handleSort = useCallback(opts => {
    var _opts$;
    if (keepSameOptionsOrder) {
      return opts;
    }
    const isGrouped = Array.isArray((_opts$ = opts[0]) == null ? void 0 : _opts$.options);
    const sortOptions = (a, b) => {
      const aSelected = selectedOptions.includes(a.id);
      const bSelected = selectedOptions.includes(b.id);
      const aMixed = mixedOptions.includes(a.id);
      const bMixed = mixedOptions.includes(b.id);
      if (aSelected && !bSelected) {
        return -1;
      }
      if (!aSelected && bSelected) {
        return 1;
      }
      if (aMixed && !bMixed) {
        return -1;
      }
      if (!aMixed && bMixed) {
        return 1;
      }
      return 0;
    };
    if (isGrouped) {
      return opts.map(group => {
        const sortedGroupOptions = group.options.sort(sortOptions);
        return {
          ...group,
          options: sortedGroupOptions
        };
      });
    } else {
      return opts.sort(sortOptions);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  const sortList = useCallback(options => {
    var _options$;
    if (disabledInternalSort) {
      return handleSort([...options]);
    }
    const isGrouped = Array.isArray((_options$ = options[0]) == null ? void 0 : _options$.options);
    if (isGrouped) {
      const sortedOptions = options.map(group => {
        const sortedGroupOptions = group.options.sort((a, b) => sortDirection === "asc" ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name));
        return {
          ...group,
          options: handleSort(sortedGroupOptions)
        };
      });
      return handleSort(sortedOptions);
    } else {
      const sortedOptions = options.sort((a, b) => sortDirection === "asc" ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name));
      return handleSort(sortedOptions);
    }
  }, [sortDirection, disabledInternalSort, handleSort]);
  const sortedList = useMemo(() => sortList(options), [options, sortList]);
  const [hover, setHover] = useState({
    item: undefined,
    by: undefined
  });
  const [filter, setFilter] = useState("");
  const handleEmpty = useCallback(e => {
    if (e && e.button !== 0) {
      return;
    }
    if (handleEmptyAction) {
      var _inputEl$current;
      inputEl == null || (_inputEl$current = inputEl.current) == null || _inputEl$current.focus();
      setFilter("");
      handleEmptyAction(filter);
    }
  }, [filter, handleEmptyAction, inputEl]);
  const onAddNewMouseEnter = useCallback(() => setHover({
    item: "addNew",
    by: "mouse"
  }), []);
  const showAddNew = useMemo(() => {
    return !!(emptyValue && filter.trim() && options.every(option => {
      if (isOptionGroup(option)) {
        return option.options.every(v => v.name.toLowerCase() !== filter.trim().toLowerCase());
      }
      return option.name.toLowerCase() !== filter.trim().toLowerCase();
    }));
  }, [emptyValue, filter, options]);
  const renderAddNew = useMemo(() => {
    return /*#__PURE__*/React.createElement(StyledAutocompleteNewItem, {
      ref: hover.item === "addNew" ? itemRef : null,
      key: "emptyValue",
      hover: hover.item === "addNew",
      onMouseDown: handleEmpty,
      onMouseEnter: onAddNewMouseEnter
    }, emptyValue);
  }, [emptyValue, handleEmpty, hover, onAddNewMouseEnter]);
  const filterOptions = useCallback((options, filter) => {
    const trimmedFilter = filter.trim();
    const isGrouped = options[0] && isOptionGroup(options[0]);
    if (isGrouped) {
      let hovered = false;
      return options.reduce((acc, groupedOption) => {
        const filteredOptions = groupedOption.options.filter(v => v.name.toLowerCase().includes(trimmedFilter.toLowerCase()));
        if (filteredOptions.length > 0) {
          if (!hovered && filter) {
            setHover({
              item: filteredOptions[0].id,
              by: "keyboard"
            });
          }
          hovered = true;
          return [...acc, {
            ...groupedOption,
            options: filteredOptions
          }];
        }
        return [...acc];
      }, []);
    } else {
      const filteredOptions = options.filter(v => v.name.toLowerCase().includes(trimmedFilter.toLowerCase()));
      if (filter && filteredOptions.length > 0) {
        setHover({
          item: filteredOptions[0].id,
          by: "keyboard"
        });
      }
      if (filteredOptions.length === 0 && emptyValue) {
        setHover({
          item: "addNew",
          by: "keyboard"
        });
      }
      return filteredOptions;
    }
  }, [emptyValue]);
  const list = useMemo(() => filterOptions(sortedList, filter), [filter, filterOptions, sortedList]);
  const showDefaultOption = useMemo(() => !!defaultValue && !filter, [defaultValue, filter]);
  const flatOptions = useMemo(() => {
    const options = list.reduce((acc, option) => {
      if (!isOptionGroup(option)) {
        return [...acc, option];
      }
      return [...acc, ...option.options];
    }, []);
    return filterOptions(options, filter);
  }, [filter, filterOptions, list]);
  const handleInputChange = useCallback(e => {
    if (e.target && !(e.key === "ArrowDown") && !(e.key === "ArrowUp") && !(e.key === "Enter")) {
      setFilter(e.target.value);
    }
  }, []);
  const handleHoverCallback = useCallback(e => {
    setHover({
      item: e,
      by: "mouse"
    });
  }, []);
  const toggleSelected = useCallback(id => {
    let result;
    if (id !== null) {
      if (type === "multiple") {
        if (selectedOptions.includes(id)) {
          result = selectedOptions.filter(_id => _id !== id);
        } else {
          result = [...selectedOptions, id];
        }
      } else {
        result = id;
      }
      if (clearInputOnSelect && inputEl != null && inputEl.current) {
        inputEl.current.value = "";
        inputEl.current.dispatchEvent(new Event("change", {
          bubbles: true
        }));
      }
      setFilter("");
    } else {
      if (typeof handleDefaultOptionChange === "function") {
        handleDefaultOptionChange();
        return;
      }
    }
    if (typeof handleChange === "function") {
      handleChange(result);
    }
  }, [clearInputOnSelect, handleChange, handleDefaultOptionChange, inputEl, selectedOptions, type]);
  const handleMouseEnter = useCallback(e => {
    if (e === undefined || e === null) {
      return setHover({
        item: null,
        by: "mouse"
      });
    }
    setHover({
      item: e,
      by: "mouse"
    });
  }, []);
  const handleClick = useCallback(e => {
    e.preventDefault();
    toggleSelected(hover.item);
  }, [toggleSelected, hover]);
  const handleRenderOption = useCallback((item, index) => {
    if (isOptionGroup(item)) {
      return /*#__PURE__*/React.createElement(OptionGroup, {
        checked: selectedOptions,
        name: item.name,
        tooltip: item.tooltip,
        key: item.id,
        setHover: handleHoverCallback,
        id: item.id,
        hover: hover.item,
        options: item.options,
        renderOptions: handleRenderOption,
        type: type,
        onChange: handleChange,
        filter: filter,
        mixedOptions: mixedOptions
      });
    }
    return /*#__PURE__*/React.createElement(Option, {
      name: item.name,
      ref: itemRef,
      key: index,
      tooltip: item.tooltip,
      onMouseEnter: handleMouseEnter,
      onClick: handleClick,
      id: item.id,
      hover: item.id === hover.item,
      className: optionClassName,
      renderOption: renderOption({
        ...item,
        name: highlightText(item.name, filter)
      }, {
        id: "option_" + item.id,
        checked: selectedOptions && selectedOptions.includes(item.id),
        hover: hover.item === item.id,
        onChange: () => null
      })
    });
  }, [handleClick, handleMouseEnter, hover.item, optionClassName, renderOption, filter, selectedOptions, handleHoverCallback, type, handleChange, mixedOptions]);
  const handleOnMouseLeave = useCallback(() => {
    setHover({
      item: undefined,
      by: "mouse"
    });
  }, []);
  const handleScroll = useCallback((list, itemOffset) => {
    if (list.getClientHeight() + list.getScrollTop() < itemOffset + 40) {
      return list.scrollTop(itemOffset - list.getClientHeight() + 30);
    }
    if (list.getScrollTop() > itemOffset) {
      return list.scrollTop(itemOffset);
    }
  }, []);
  useEffect(() => {
    if (hover.by === "keyboard" && hover.item !== undefined) {
      const item = itemRef.current;
      const list = listRef.current;
      if (itemRef && item && list) {
        handleScroll(list, item.offsetTop);
      }
    }
  }, [handleScroll, hover]);
  const handleOnKeyDown = useCallback(e => {
    if (e.key === "Enter") {
      e.preventDefault();
      if (hover.item === undefined && filter === "") {
        return;
      }
      if (hover.item === "addNew") {
        handleEmpty(null);
        return;
      }
      if (hover.item === null && handleDefaultOptionChange) {
        handleDefaultOptionChange();
        return;
      }
      if (typeof hover.item !== "undefined" || hover.item !== null) {
        toggleSelected(hover.item);
        setFilter("");
      }
      return;
    }
    setHover({
      item: handleKeyboardMovement(e, hover.item, flatOptions, showAddNew, showDefaultOption),
      by: "keyboard"
    });
  }, [filter, flatOptions, toggleSelected, handleDefaultOptionChange, handleEmpty, hover, showAddNew, showDefaultOption]);
  useEffect(() => {
    var _inputEl$current2;
    const listenerTarget = (_inputEl$current2 = inputEl == null ? void 0 : inputEl.current) != null ? _inputEl$current2 : document;
    listenerTarget.addEventListener("input", handleInputChange);
    listenerTarget.addEventListener("keydown", handleOnKeyDown);
    return () => {
      listenerTarget.removeEventListener("input", handleInputChange);
      listenerTarget.removeEventListener("keydown", handleOnKeyDown);
    };
  }, [handleInputChange, handleOnKeyDown, inputEl]);
  const isDefaultOptionSelected = useCallback(() => {
    if (preselectDefaultValue) {
      return selectedOptions.length < 1 || selectedOptions[0] === "";
    } else {
      return selectedOptions[0] === null || selectedOptions.length === flatOptions.length;
    }
  }, [flatOptions.length, preselectDefaultValue, selectedOptions]);
  const showNoResult = useMemo(() => noResultText && !showAddNew && list.length < 1 && (defaultValue && filter || !defaultValue), [noResultText, showAddNew, list.length, defaultValue, filter]);
  const renderNoResult = useMemo(() => /*#__PURE__*/React.createElement(_StyledStyledOption, null, noResultText), [noResultText]);
  return /*#__PURE__*/React.createElement(StyledAutocompleteScrollShadow, {
    className: AutocompleteClassName,
    $isHidden: !defaultValue && !emptyValue && !noResultText && list.length < 1
  }, _ref2 => {
    let {
      onScroll
    } = _ref2;
    return /*#__PURE__*/React.createElement(StyledAutocompleteBody, {
      key: "body",
      onMouseLeave: handleOnMouseLeave
    }, /*#__PURE__*/React.createElement(Scrollbars, {
      ref: listRef,
      key: "scrollBar",
      autoHeight: true,
      autoHeightMax: autoHeightMax,
      onScroll: onScroll
    }, defaultValue && !filter && /*#__PURE__*/React.createElement(Option, {
      name: defaultValue,
      ref: itemRef,
      hover: hover.item === null,
      onMouseEnter: handleMouseEnter,
      onClick: e => {
        e.preventDefault();
        toggleSelected(null);
      },
      renderOption: renderOption({
        name: defaultValue,
        id: null
      }, {
        checked: isDefaultOptionSelected(),
        hover: hover.item === null,
        onChange: () => null
      })
    }), list.map((item, index) => handleRenderOption(item, index)), showNoResult && renderNoResult, showAddNew && renderAddNew));
  });
};
Autocomplete.displayName = "Autocomplete";
var _StyledStyledOption = _styled(StyledOption).withConfig({
  displayName: "Autocomplete___StyledStyledOption",
  componentId: "sc-9x4q7e-0"
})(["cursor:auto"]);
//# sourceMappingURL=Autocomplete.js.map