import React, { useCallback, useEffect, useMemo } from 'react';
import ReactSelect, { GroupBase, SelectComponentsConfig, SingleValue as ReactSelectSingleValue } from 'react-select';
import {
  BaseControl,
  BaseGroup,
  BaseOption,
  BasePlaceholder,
  IndicatorContainer,
  MenuList,
  MenuPortal,
  MenuWrapper,
  SelectContainer,
  SingleValue,
  ValueContainer,
} from '../components';
import {
  BaseCustomReactSelectProps,
  BaseOption as BaseOptionType,
  BaseSelectProps,
  MenuPlacement,
  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,
  dataSelector,
  customReactSelectProps,
  selectRef,
  ...selectProps
}: BaseSelectProps<T, P> & SelectMenuProps) => {
  const handleMenu = useCallback(
    (event: React.MouseEvent<HTMLDivElement>, menuIsOpen: boolean) => {
      event.stopPropagation();

      if (menuIsOpen) {
        closeMenu();
      } else {
        openMenu();
      }
    },
    [closeMenu, openMenu]
  );

  const handleChange = useCallback(
    (option: ReactSelectSingleValue<T>) => {
      closeMenu();

      if (option) {
        valueHandler(option.id);
      }
    },
    [closeMenu, valueHandler]
  );

  const components = useMemo<SelectComponentsConfig<T, false, GroupBase<T>>>(
    () => ({
      Control: BaseControl,
      ValueContainer: ValueContainer,
      SingleValue: SingleValue,
      IndicatorSeparator: null,
      DropdownIndicator: IndicatorContainer,
      MenuList: MenuList,
      Menu: MenuWrapper,
      Group: BaseGroup,
      Option: BaseOption,
      SelectContainer: SelectContainer,
      Placeholder: BasePlaceholder,

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

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

  const customSelectProps = useMemo<BaseCustomReactSelectProps>(
    () => ({
      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={selectRef}
      menuIsOpen={isMenuOpen}
      getOptionLabel={({ value }) => value}
      options={selectProps.options}
      menuPortalTarget={document.body}
      menuShouldBlockScroll={false}
      captureMenuScroll={false}
      isMulti={false}
      {...selectProps}
      onChange={handleChange}
      components={components}
      // @ts-ignore
      customSelectProps={customSelectProps}
    />
  );
};

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