import React, { useCallback, useEffect, useMemo } from 'react';
import ReactSelect, { MultiValue as ReactSelectMultiValue, SelectComponentsConfig } from 'react-select';
import {
  BaseControl,
  BaseGroup,
  BaseOption,
  IndicatorContainer,
  MenuList,
  MenuPortal,
  MultiValueContainer,
  MultiValuePlaceholder,
  MultiValueRemove,
  SearchableMenuWrapper,
  SelectContainer,
  SingleValue,
  ValueContainer,
} from '../components';
import {
  BaseGroup as BaseGroupType,
  BaseMultiSelectProps,
  BaseOption as BaseOptionType,
  MenuPlacement,
  MultiCustomReactSelectProps,
  SelectMenuProps,
} from '../types';
import { SELECT_ID } from 'common/components/select/constants';

const Root = <T extends BaseOptionType, P extends {}>({
  classNames,
  placement = MenuPlacement.Auto,
  isMenuOpen,
  openMenu,
  closeMenu,
  valueHandler,
  selectComponents,
  onFocus,
  dataSelector,
  customReactSelectProps,
  ...selectProps
}: BaseMultiSelectProps<T, P> & SelectMenuProps) => {
  const handleMenu = useCallback(
    (event: React.MouseEvent<HTMLDivElement>, menuIsOpen: boolean) => {
      if (menuIsOpen) {
        closeMenu();
      } else {
        openMenu();
      }
    },
    [closeMenu, openMenu]
  );

  const handleChange = useCallback(
    (option: ReactSelectMultiValue<T>) => {
      valueHandler(option.map(option => option.id));
    },
    [valueHandler]
  );

  const components: SelectComponentsConfig<T, true, BaseGroupType<T>> = useMemo(
    () => ({
      Control: BaseControl,
      ValueContainer: ValueContainer,
      SingleValue: SingleValue,
      IndicatorSeparator: null,
      DropdownIndicator: IndicatorContainer,
      Menu: SearchableMenuWrapper,
      MenuList: MenuList,
      Group: BaseGroup,
      Option: BaseOption,
      MultiValueContainer: MultiValueContainer,
      MultiValueRemove: MultiValueRemove,
      Placeholder: MultiValuePlaceholder,
      ClearIndicator: () => null,
      SelectContainer: SelectContainer,

      ...selectComponents?.({
        isMenuOpen,
        openMenu,
        closeMenu,
      }),

      MenuPortal: MenuPortal,
    }),
    [closeMenu, isMenuOpen, openMenu, selectComponents]
  );

  const customSelectProps = useMemo<MultiCustomReactSelectProps>(
    () => ({
      handleMenu: handleMenu,
      classNames: classNames,
      closeMenu: closeMenu,
      portalPlacement: placement,
      dataSelector: dataSelector,

      ...customReactSelectProps,
    }),
    [classNames, closeMenu, customReactSelectProps, dataSelector, handleMenu, placement]
  );

  useEffect(() => {
    if (selectProps.closeMenuOnScroll) {
      document.addEventListener('scroll', closeMenu);
    }

    return () => {
      document.removeEventListener('scroll', closeMenu);
    };
  }, [closeMenu, selectProps.closeMenuOnScroll]);

  return (
    <ReactSelect
      id={SELECT_ID}
      ref={selectProps.selectRef}
      menuIsOpen={isMenuOpen}
      getOptionLabel={({ value }) => value}
      options={selectProps.options}
      menuPortalTarget={document.body}
      menuShouldBlockScroll={false}
      captureMenuScroll={false}
      blurInputOnSelect={false}
      isMulti={true}
      isClearable={selectProps.isClearable}
      backspaceRemovesValue={true}
      {...selectProps}
      onChange={handleChange}
      onFocus={onFocus}
      components={components}
      // @ts-ignore
      customSelectProps={customSelectProps}
    />
  );
};

export const BaseMultiSelect = React.memo(Root) as typeof Root;
