import { find, flatMapDeep } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
  BadgeSelect,
  BaseSelect,
  SearchableSelect,
  SearchableSimpleSelect,
  SimpleSelect,
  TreeSelect,
} from './containers';
import { isOptionsGroup } from './guards';
import {
  BadgeSelectProps,
  BaseOption as BaseOptionType,
  BaseSelectProps,
  SearchableSelectProps,
  SearchableSimpleSelectProps,
  SelectType,
  SimpleSelectProps,
  TreeSelectProps,
} from './types';

const Root = <T extends BaseOptionType, P extends {} = {}>(
  props:
    | BaseSelectProps<T, P>
    | SimpleSelectProps<T>
    | BadgeSelectProps<T>
    | SearchableSelectProps<T>
    | SearchableSimpleSelectProps<T>
    | TreeSelectProps<T>
) => {
  const { type, valueId, isDisabled, isOpened } = props;

  const [isMenuOpen, setIsMenuOpen] = useState(false);

  const flattenedOptions = useMemo(
    () => flatMapDeep(props.options, option => (isOptionsGroup(option) ? option.options : option)),
    [props.options]
  );

  const value = useMemo(() => find(flattenedOptions, ({ id }) => id === valueId) || null, [flattenedOptions, valueId]);

  const openMenu = useCallback(() => {
    if (isDisabled) return;
    setIsMenuOpen(true);
  }, [isDisabled]);

  const closeMenu = useCallback(() => {
    setIsMenuOpen(false);
  }, []);

  useEffect(() => {
    if (isOpened !== undefined) {
      requestAnimationFrame(() => {
        setIsMenuOpen(isOpened);
      });
    }
  }, [isOpened]);

  switch (type) {
    case SelectType.Base:
      return <BaseSelect {...props} value={value} isMenuOpen={isMenuOpen} openMenu={openMenu} closeMenu={closeMenu} />;
    case SelectType.Simple:
      return (
        <SimpleSelect {...props} value={value} isMenuOpen={isMenuOpen} openMenu={openMenu} closeMenu={closeMenu} />
      );
    case SelectType.Badge:
      return <BadgeSelect {...props} value={value} isMenuOpen={isMenuOpen} openMenu={openMenu} closeMenu={closeMenu} />;
    case SelectType.Searchable:
      return (
        <SearchableSelect {...props} value={value} isMenuOpen={isMenuOpen} openMenu={openMenu} closeMenu={closeMenu} />
      );
    case SelectType.SearchableSimple:
      return (
        <SearchableSimpleSelect
          {...props}
          value={value}
          isMenuOpen={isMenuOpen}
          openMenu={openMenu}
          closeMenu={closeMenu}
        />
      );
    case SelectType.Tree:
      return <TreeSelect {...props} value={value} isMenuOpen={isMenuOpen} openMenu={openMenu} closeMenu={closeMenu} />;
  }
};

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