/**
 * TEAM: frontend_infra
 * @flow strict
 */

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
// TODO: Fix this eslint issue on next edit. This is an autogenerated comment.
// eslint-disable-next-line flexport/no-legacy-dependencies
import {zIndices} from "latitude/tools/deprecatedZIndices";
import useDropdown from "./tools/useDropdown";
import TextInput from "./TextInput";
import DropdownList from "./select/DropdownList";
import PopupWithClickAway from "./popup/PopupWithClickAway";
import StackingContext from "./StackingContext";

type Option = string;

type TextInputProps = React.ElementConfig<typeof TextInput>;

type Props = {|
  /** all TextInput props will be passed into the TextInput */
  ...TextInputProps,
  +suggestions: $ReadOnlyArray<Option>,
  /**
   * positively filters an suggestion according to the callback. Specify `null` to
   * not filter suggestions
   */
  +suggestionsFilter?: ((query?: string, option: Option) => boolean) | null,
  /** the maximum number of suggestions that will be presented */
  +maximumOptions?: number,
  /** the suggestion to highlight for keyboard selection, can be a function that
   * returns what suggestion to highlight on value change */
  +highlight?: string | ((?string) => ?string),
|};

export const defaultFilter = (query?: string, option: Option): boolean => {
  const trimmedOption = option.toLowerCase().trim();
  const trimmedQuery = query?.toLowerCase().trim();

  return trimmedQuery != null && trimmedOption.includes(trimmedQuery);
};

/**
 * @category Data Entry
 * @short Collect simple text input from the user with dropdown suggestions
 * @brandStatus V2
 * @status Stable
 * TextInputAutocomplete is a text input with a suggestions dropdown. By default a maximum
 * of 10 suggestions are displayed by the dropdown.
 */
export default function TextInputAutocomplete({
  suggestions,
  suggestionsFilter = defaultFilter,
  maximumOptions = 10,
  value,
  highlight,
  ...textInputProps
}: Props): React.Node {
  const filteredSuggestions = suggestions
    .filter((option: string) =>
      suggestionsFilter ? suggestionsFilter(value, option) : true
    )
    .slice(0, maximumOptions);

  const popper = React.useRef();

  const handleChange = (newValue: string) => {
    textInputProps.onChange(newValue);

    if (typeof highlight === "function") {
      const valueToHighlight = highlight(newValue);

      if (valueToHighlight != null) {
        setHighlightedLabel(valueToHighlight);
      }
    }
  };

  const {highlightedIndex, handlers, setHighlightedLabel} = useDropdown(
    filteredSuggestions,
    {
      popper,
      onChange: handleChange,
      onMouseDown: e => {
        if (textInputProps.onClick) {
          textInputProps.onClick(e);
        }
      },
      onFocus: e => {
        if (textInputProps.onFocus) {
          textInputProps.onFocus(e);
        }
      },
      onBlur: e => {
        if (textInputProps.onBlur) {
          textInputProps.onBlur(e);
        }
      },
      onKeyDown: e => {
        if (textInputProps.onKeyDown) {
          textInputProps.onKeyDown(e);
        }
      },
    }
  );

  const {isDeprecatedZIndexEnabled} = React.useContext(StackingContext);

  if (typeof highlight === "string") setHighlightedLabel(highlight);

  return (
    <PopupWithClickAway ref={popper}>
      {(Target, Popup) => (
        <div className={css(styles.container)}>
          <Target>
            <TextInput
              {...textInputProps}
              value={value}
              onChange={handlers.handleChange}
              onMouseDown={handlers.handleMouseDown}
              onFocus={handlers.handleFocus}
              onBlur={handlers.handleBlur}
              onKeyDown={handlers.handleKeyDown}
            />
          </Target>
          <Popup
            placement="bottom-start"
            zIndex={zIndices.zIndex1500AboveModal.zIndex}
            noPortal={true}
          >
            <div
              tabIndex={-1}
              onFocus={handlers.handleFocus}
              onBlur={handlers.handleBlur}
              className={css(
                styles.dropdownContainer,
                isDeprecatedZIndexEnabled && styles.dropdownContainerZIndex
              )}
            >
              <DropdownList
                options={filteredSuggestions.map(suggestion => ({
                  label: suggestion,
                }))}
                highlightedOption={
                  highlightedIndex != null
                    ? filteredSuggestions[highlightedIndex]
                    : null
                }
                onClick={handlers.handleItemClick}
              />
            </div>
          </Popup>
        </div>
      )}
    </PopupWithClickAway>
  );
}

const styles = StyleSheet.create({
  container: {
    position: "relative",
  },
  dropdownContainer: {
    position: "absolute",
    left: "0",
    top: "100%",
    padding: "6px 0",
    minWidth: "100%",
    transform: "none",
  },
  dropdownContainerZIndex: {
    // eslint-disable-next-line flexport/no-zindex-except-specific-values
    zIndex: "10",
  },
});
