import cn from "classnames";
import React, { forwardRef, useImperativeHandle, useEffect, useCallback, ReactNode } from "react";
import Dropdown, { InputHandlers, IDropdownProps } from "../dropdown/dropdown";
import Search from "../search/search";
import Context from "./select-context";

export interface ISelect extends IDropdownProps {
  controls?: ReactNode | ReactNode[];
  loading?: boolean;
  onLazyLoad?: () => void;
  onSearch?: (value: string) => void;
  searchClassName?: string;
  searchDebounce?: number;
  searchLabel?: string;
  selectAppend?: ReactNode;
  selectPrepend?: ReactNode;
  wrapperClassName?: string;
}

const Select = forwardRef<InputHandlers, ISelect>((props, ref) => {
  const {
    btnClassName,
    btnVariant,
    controls,
    header,
    loading,
    maxHeight,
    maxWidth,
    minHeight,
    minWidth,
    onLazyLoad,
    onSearch,
    position,
    searchClassName,
    searchDebounce,
    searchLabel,
    selectAppend,
    selectPrepend,
    wrapperClassName,
    ...rest
  } = props;
  const actions = React.createRef<InputHandlers>();
  const btnRef = React.createRef<HTMLButtonElement>();
  const scrollRef = React.createRef<HTMLDivElement>();
  const [selectWidth, setSelectWidth] = React.useState(0);

  if (onSearch && !searchLabel) {
    console.warn("Select: searchLabel must be provided for Search input");
  }

  useImperativeHandle(ref, () => ({
    closeDropdown() {
      if (actions && actions.current) {
        actions.current.closeDropdown();
      }
    }
  }));

  useEffect(() => {
    if (!btnRef.current) {
      return;
    }
    setSelectWidth(btnRef.current.offsetWidth);
  }, []);

  const onScroll = useCallback(() => {
    if (!onLazyLoad || !scrollRef.current) {
      return;
    }
    if (
      scrollRef.current.scrollTop + scrollRef.current.clientHeight >=
      scrollRef.current.scrollHeight
    ) {
      onLazyLoad();
    }
  }, [scrollRef]);

  return (
    <Context.Provider value={{}}>
      <Dropdown
        arrow
        btnClassName={cn("d-flex align-items-center justify-content-between w-100", btnClassName)}
        btnRef={btnRef}
        btnVariant={btnVariant || "outline-secondary"}
        header={<div className="text-truncate">{header}</div>}
        maxHeight="auto"
        maxWidth={selectWidth}
        minWidth={selectWidth}
        position={position || "left"}
        ref={actions}
        {...rest}
      >
        <>
          {loading ? (
            <div
              className="d-flex justify-content-center align-items-center position-absolute w-100 h-100"
              style={{ zIndex: 4 }}
            >
              {/* TODO use honeyUI loader */}
              <div style={{ opacity: 0.3 }} className="position-absolute w-100 h-100 bg-dark" />
              <div className="spinner-border" role="status">
                <span className="sr-only"></span>
              </div>
            </div>
          ) : null}

          {onSearch ? (
            <div className={cn("p-2", searchClassName)}>
              <Search
                onChange={onSearch}
                ariaLabel={searchLabel}
                placeholder={searchLabel}
                debounce={searchDebounce}
                size="sm"
              />
            </div>
          ) : null}

          {selectAppend}

          <div
            ref={scrollRef}
            className={cn("overflow-auto", wrapperClassName)}
            style={{ maxHeight, maxWidth: selectWidth }}
            onScroll={onScroll}
          >
            {props.children}
          </div>

          {selectPrepend}

          {controls}
        </>
      </Dropdown>
    </Context.Provider>
  );
});

Select.displayName = "Select";
Select.defaultProps = {
  maxHeight: 284,
  maxWidth: 300,
  minWidth: 300
};

export default Select;
