import classNames from "classnames";
import React, { useRef, useState } from "react";
import { useKeyPress, useOutsideClick } from "../../hooks";
import { KEY_CODE } from "../../types";
import { bem } from "../../utilities/bem";
import { BoxProps, Box } from "../Box";
import { Button, BUTTON_VARIANT } from "../Button";
import { Flex } from "../Flex";
import { ICON_TYPE, Icon } from "../Icon";

const cn = "SearchFilter";

export enum SEARCH_FILTER_DIRECTION {
  LEFT = "left",
  RIGHT = "right",
}

export interface SearchFilterProps extends BoxProps {
  /**
   * Current value of the search input
   */
  inputValue: string;
  /**
   * Handler for the onChange event of the search input
   */
  onInputChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
  /**
   * Handler for the onSubmit event of the search form.
   */
  onSearchSubmit: (event: React.FormEvent<HTMLFormElement>) => void;
  /**
   * Called when the input is cleared (only available if autoClose is false) and should be used to clear the input since this is a controlled component
   */
  onClear?: (event: React.MouseEvent<HTMLButtonElement>) => void;
  /**
   * If false, the search input will remain in the open state and not be closed when it loses focus
   */
  autoClose?: boolean;
  /**
   * Callback to execute when the input is collapsed.  If using autoClose mode, this should be used to clear the inputValue.
   */
  onClose?: () => void;
  /**
   * The direction (relative to the button) to which the input should expand when opened.
   */
  direction?: SEARCH_FILTER_DIRECTION;
  /**
   * Placeholder text for the input
   */
  placeholder?: string;
}

export const SearchFilter = ({
  className,
  direction = SEARCH_FILTER_DIRECTION.LEFT,
  placeholder = "Search",
  inputValue,
  onInputChange,
  onSearchSubmit,
  onClear,
  autoClose = true,
  onClose,
  ...rest
}: SearchFilterProps) => {
  const Component = autoClose ? "button" : "div";
  const [isOpen, setIsOpen] = useState(!autoClose);
  const searchElement = useRef<HTMLDivElement>(null);
  const inputElement = useRef<HTMLInputElement>(null);

  const focusInput = () => {
    if (inputElement && inputElement.current) {
      inputElement.current.focus();
    }
  };

  const blurInput = () => {
    if (inputElement && inputElement.current) {
      inputElement.current.blur();
    }
  };

  const openSearch = () => {
    setIsOpen(true);
    focusInput();
  };

  const closeSearch = () => {
    setIsOpen(false);
    blurInput();
    if (onClose) {
      onClose();
    }
  };

  const toggleSearchInput = () => {
    if (isOpen) {
      closeSearch();
    } else {
      openSearch();
    }
  };

  const handleToggleClick = () => {
    if (autoClose) {
      toggleSearchInput();
    }
  };

  useOutsideClick(searchElement, () => {
    if (autoClose) {
      closeSearch();
    }
  });

  useKeyPress(KEY_CODE.ESC, () => {
    if (autoClose) {
      closeSearch();
    }
  });

  const ToggleButton = () => {
    return (
      <Component
        className={classNames(
          bem(cn, { e: "toggle-button" }),
          autoClose && bem(cn, { e: "toggle-button", m: "autoClose" }),
          isOpen && bem(cn, { e: "toggle-button", m: "isOpen" }),
        )}
        onClick={handleToggleClick}
      >
        <Icon icon={ICON_TYPE.SEARCH} />
      </Component>
    );
  };

  return (
    <Box
      ref={searchElement}
      className={classNames(
        className,
        bem(cn),
        isOpen && bem(cn, { m: "isOpen" }),
        bem(cn, { m: direction }),
      )}
      {...rest}
    >
      {direction === SEARCH_FILTER_DIRECTION.RIGHT && <ToggleButton />}
      <form onSubmit={onSearchSubmit}>
        <Flex className="items-center h-full">
          <input
            ref={inputElement}
            className={classNames(
              bem(cn, { e: "input" }),
              isOpen && bem(cn, { e: "input", m: "isOpen" }),
            )}
            value={inputValue}
            placeholder={placeholder}
            tabIndex={isOpen ? 0 : -1}
            onChange={onInputChange}
            type="text"
          />
          {autoClose && isOpen && (
            <Button
              type="submit"
              className={classNames(bem(cn, { e: "submit-button" }))}
              variant={BUTTON_VARIANT.SECONDARY}
              icon={ICON_TYPE.ARROW_RIGHT}
            />
          )}
          {!autoClose && onClear && (
            <Button
              type="button"
              className={classNames(
                bem(cn, { e: "clear-button" }),
                !inputValue && "invisible",
              )}
              variant={BUTTON_VARIANT.SECONDARY}
              icon={ICON_TYPE.TIMES}
              onClick={onClear}
            />
          )}
        </Flex>
      </form>
      {direction === SEARCH_FILTER_DIRECTION.LEFT && <ToggleButton />}
    </Box>
  );
};
