import {
  concat,
  isEmpty,
  sortBy as lodashSortBy,
  times,
  uniqBy,
  xorBy,
} from 'lodash';
import PropTypes from 'prop-types';
import React, { useEffect, useRef, useState } from 'react';
import { ThemeProvider } from 'styled-components';
import i18next from 'i18next';
import Checkbox from '../Checkbox';

import {
  CheckboxContainer,
  Container,
  DropdownButton,
  DropdownItem,
  DropdownItemTag,
  DropdownItemText,
  DropdownList,
  DropdownListContainer,
  Icon,
  InputContainer,
  LabelContainer,
  LabelRequiredCharacter,
  LoadingDropdownItem,
  LoadingDropdownListContainer,
  MultiselectValidationButton,
  SearchInput,
  SearchInputItem,
  SpinnerImg,
  Text,
} from './styledComponents';

import SpinnerIcon from '../images/icon-loading-state-lgrey.svg';
import carretUpIconBlack from '../images/icon-carret-up-ipblack.svg';
import carretUpIconRed from '../images/icon-carret-up-red.svg';
import carretDownIconRed from '../images/icon-carret-down-red.svg';
import carretDownIconBlack from '../images/icon-carret-down-ipblack.svg';
import carretDownIconDmGrey from '../images/icon-carret-down-dmgrey.svg';
import carretDownIconWhite from '../images/icon-carret-down-white.svg';
import checkIconBlack from '../images/icon-check-ipblack.svg';
import checkIconWhite from '../images/icon-check-white.svg';
import searchIconBlack from '../images/icon-search-ipblack.svg';
import searchIconDmGrey from '../images/icon-search-dmgrey.svg';
import searchIconWhite from '../images/icon-search-white.svg';
import closeIconBlack from '../images/icon-close-ipblack.svg';
import iconNewTabBlack from '../images/icon-new-tab-black.svg';

import { Item, Props } from './interfaces';

import { getTheme } from '../utils/theme';
import { normalizeString } from '../utils/format';
import Tooltip from '../Tooltip';

const MIN_NB_ITEMS_BEFORE_DISPLAYING_SEARCH = 1;
const NUMBER_OF_LOADING_DROPDOWN_ITEMS_TO_DISPLAY = 9;

const TYPES_OF_DATA_TO_FETCH = {
  RESET_FETCH: 'RESET_FETCH',
  LOAD_MORE_DATA: 'LOAD_MORE_DATA',
};

// Used for reference : https://stackoverflow.com/questions/32553158/detect-click-outside-react-component
const useOutsideAlerter = (ref, handleCloseDropdown) => {
  useEffect(() => {
    const handleClickOutside = (event) => {
      if (ref.current && !ref.current.contains(event.target)) {
        handleCloseDropdown();
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  });
};

const Dropdown = (props: Props): JSX.Element => {
  const {
    theme,
    items,
    width,
    height,
    customStyle,
    iconSrc,
    placeholder,
    label,
    selectedItems,
    isDisabled,
    isRequired,
    isErrorState,
    isSearchDisabled,
    searchPlaceholder,
    iconCustomStyle,
    isUniqueSelection,
    onSelectionChange,
    onTriggerDropdownList,
    button,
    sortBy,
    labelStyle,
    customListStyle,
    tooltipText,
    shouldInterpretTooltipHTML,
    link,
    searchDebounceTimeInMs,
    pagination,
    customDropdownListStyle,
    languageCode,
    displayName,
    largeDropdownList,
    maxSelection,
  } = props;

  const [shouldDisplayDropdownList, setShouldDisplayDropdownList] =
    useState<boolean>(false);

  const [dropdownSearchValue, setDropdownSearchValue] = useState<string>('');

  // To avoid side effects with the non paginated dropdownSearchValue
  const [paginationDropdownSearchValue, setPaginationDropdownSearchValue] =
    useState<string>('');

  const [isListLoading, setIsListLoading] = useState<boolean>(
    pagination?.isLoading || false
  );
  const [isSearchLoading, setIsSearchLoading] = useState<boolean>(
    pagination?.isLoading || false
  );
  const [isLoadingMoreResult, setIsLoadingMoreResult] =
    useState<boolean>(false);

  const [matchingItems, setMatchingItems] = useState<Item[]>(items);
  const [isSearching, setIsSearching] = useState<boolean>(false);

  const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout>();

  const [tmpSelectedItems, setTmpSelectedItems] =
    useState<Item[]>(selectedItems);

  const updatedTheme = getTheme(theme, 'dropdown');
  const wrapperRef = useRef<HTMLInputElement>(null);

  const searchInputRef = useRef<HTMLInputElement>(null);

  const [scrollValue, setScrollValue] = useState(0);

  const getDisplayValue = (item: Item): string => {
    if (displayName && item.name) {
      return item.name;
    }
    return item.value;
  };

  const isSelected = (elements: Item[], element: Item): boolean => {
    return elements.some(({ id }) => id === element.id);
  };

  const isDisabledItem = (item: Item): boolean =>
    item.isDisabled ||
    (!!maxSelection &&
      tmpSelectedItems.length >= maxSelection &&
      !isSelected(tmpSelectedItems, item));

  const handleCloseDropdown = () => {
    if (pagination?.handleFetchMoreData) {
      pagination.handleFetchMoreData(null);
    }

    setShouldDisplayDropdownList(false);
    setDropdownSearchValue('');
    setPaginationDropdownSearchValue('');
    setMatchingItems(items);
  };

  useOutsideAlerter(wrapperRef, handleCloseDropdown);

  useEffect(() => {
    i18next.changeLanguage(languageCode);
  }, [languageCode]);

  useEffect(() => {
    const dropdownListElem = document.getElementById('dropdown-list');

    if (dropdownListElem) {
      dropdownListElem.removeEventListener('scroll', () => {});

      dropdownListElem.addEventListener('scroll', () => {
        setScrollValue(dropdownListElem.scrollTop);
      });
    }

    if (isLoadingMoreResult) {
      setIsLoadingMoreResult(false);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [matchingItems]);

  /* **************** */
  /* Callback methods */
  /* **************** */

  useEffect(() => {
    if (dropdownSearchValue === '') {
      setMatchingItems(items);
      return;
    }

    const cleanDropdownSearchValue = normalizeString(dropdownSearchValue);

    const filteredMatchingItems = items.filter((item) =>
      normalizeString(item.value).includes(cleanDropdownSearchValue)
    );

    setMatchingItems(filteredMatchingItems);
  }, [items, dropdownSearchValue]);

  useEffect(() => {
    if (pagination?.isLoading && isLoadingMoreResult) {
      setIsListLoading(false);
      setIsSearchLoading(false);
      return;
    }

    if (pagination?.isLoading && !isSearching) {
      setIsSearchLoading(true);
      return;
    }

    setIsSearchLoading(false);
  }, [isSearching, pagination?.isLoading, isLoadingMoreResult]);

  const sortItemsList = (itemsList: Item[]): Item[] => {
    /* The value -1 is present for the case of 'None' in the application whose item has an id equal to null.
    As this generic component does not accept null ids and in order not to match with another id, the value is set to -1. */
    const mandatoryFirstItem = itemsList.filter((item) => item.id === -1);

    const itemsWithoutMandatory = itemsList.filter((item) => item.id !== -1);

    if (!sortBy) {
      return mandatoryFirstItem.concat(itemsWithoutMandatory);
    }

    return mandatoryFirstItem.concat(sortBy(itemsWithoutMandatory));
  };

  const customDebounce = (value) => {
    if (timeoutId) {
      clearTimeout(timeoutId);
    }

    if (pagination) {
      setIsListLoading(true);
    }

    const currentTimout = setTimeout(() => {
      if (pagination?.handleFetchMoreData) {
        setIsListLoading(false);

        if (value === '') {
          pagination.handleFetchMoreData(TYPES_OF_DATA_TO_FETCH.RESET_FETCH);
          return;
        }

        pagination.handleFetchMoreData(value);
        return;
      }

      setDropdownSearchValue(value.toLowerCase());
    }, searchDebounceTimeInMs);

    setTimeoutId(currentTimout);
  };

  const changeSearchValue = (value): void => {
    if (isDisabled) {
      return;
    }

    setIsSearching(!isEmpty(value));
    if (button) {
      setDropdownSearchValue(value.toLowerCase());
      return;
    }

    if (pagination) {
      setPaginationDropdownSearchValue(value.toLowerCase());
    }

    customDebounce(value);
  };

  const resetSearchValue = (): void => {
    if (searchInputRef.current) {
      searchInputRef.current.value = '';

      setDropdownSearchValue('');
      setMatchingItems(items);

      if (pagination) {
        setPaginationDropdownSearchValue('');
      }
    }
  };

  const triggerDropdownList = (): void => {
    if (isDisabled) {
      return;
    }
    if (onTriggerDropdownList) {
      onTriggerDropdownList(!shouldDisplayDropdownList);
    }
    setShouldDisplayDropdownList(!shouldDisplayDropdownList);
    setTmpSelectedItems(selectedItems);
    resetSearchValue();
  };

  const isSelectAllChecked = (): boolean => {
    return matchingItems.every((item) => {
      if (item.isDisabled) {
        return true;
      }

      return isSelected(tmpSelectedItems, item);
    });
  };

  const selectItem = (item: Item): void => {
    if (isDisabledItem(item)) {
      return;
    }

    if (isUniqueSelection) {
      const shouldUnselectItem = isSelected(selectedItems, item) && !isRequired;

      onSelectionChange(
        shouldUnselectItem ? null : item, // newly selected (or not) item
        item, // item on which user clicked
        shouldUnselectItem // whether user unselected item
      );

      triggerDropdownList();

      return;
    }

    let isAlreadySelected = false;

    const updatedSelection: Item[] = tmpSelectedItems.reduce(
      (result: Item[], current: Item) => {
        if (current.id === item.id) {
          isAlreadySelected = true;

          return result;
        }

        result.push(current);

        return result;
      },
      []
    );

    if (!isAlreadySelected) {
      updatedSelection.push(item);
    }

    setTmpSelectedItems(updatedSelection);
  };

  const selectAllMatchingItems = (): void => {
    if (!isSelectAllChecked()) {
      const allItemsSelected = concat(
        tmpSelectedItems,
        matchingItems.filter((item) => !item.isDisabled)
      );
      setTmpSelectedItems(uniqBy(allItemsSelected, 'id'));
      return;
    }
    setTmpSelectedItems(
      xorBy(
        tmpSelectedItems,
        matchingItems.filter((item) => !item.isDisabled),
        'id'
      )
    );
  };

  const isValidationDisabled = (): boolean => {
    if (isRequired && tmpSelectedItems.length === 0) {
      return true;
    }

    if (xorBy(tmpSelectedItems, selectedItems, 'id').length === 0) {
      return true;
    }

    return false;
  };

  const validateSelection = (): void => {
    if (!isValidationDisabled) {
      return;
    }

    triggerDropdownList();

    onSelectionChange(tmpSelectedItems);
  };

  const handleKeyDownSearchValue = (event): void => {
    // Early return if key not handled
    if (event.key !== 'Enter') {
      return;
    }

    // Eearly return if there is not only on matching item
    if (matchingItems.length !== 1) {
      return;
    }

    selectItem(matchingItems[0]);
  };

  /* ************** */
  /* Render methods */
  /* ************** */

  const getInputText = (): string => {
    if (!selectedItems.length) {
      return placeholder;
    }

    const selectedItemsSorted = sortItemsList(selectedItems);

    if (isUniqueSelection || selectedItems.length === 1) {
      return getDisplayValue(selectedItemsSorted[0]);
    }

    return `${getDisplayValue(selectedItemsSorted[0])} (+${
      selectedItemsSorted.length - 1
    })`;
  };

  const getInputCarretIcon = (): React.FunctionComponent<
    React.SVGAttributes<SVGElement>
  > => {
    if (isErrorState) {
      return shouldDisplayDropdownList ? carretUpIconRed : carretDownIconRed;
    }

    if (selectedItems.length) {
      return shouldDisplayDropdownList
        ? carretUpIconBlack
        : carretDownIconBlack;
    }

    if (shouldDisplayDropdownList) {
      return carretUpIconBlack;
    }

    if (isDisabled) {
      return carretDownIconWhite;
    }

    return carretDownIconDmGrey;
  };

  const getInputSearchIcon = (): React.FunctionComponent<
    React.SVGAttributes<SVGElement>
  > => {
    if (isSearchLoading) {
      return searchIconWhite;
    }

    if (!dropdownSearchValue) {
      return searchIconDmGrey;
    }

    return searchIconBlack;
  };

  const shouldDisplaySearchInput = () => {
    return items.length >= MIN_NB_ITEMS_BEFORE_DISPLAYING_SEARCH;
  };

  const renderDropdownLabel = () => {
    return (
      <LabelContainer
        isRequired={isRequired}
        isDisabled={isDisabled}
        labelStyle={labelStyle}
      >
        {isRequired && (
          <LabelRequiredCharacter isDisabled={isDisabled}>
            *
          </LabelRequiredCharacter>
        )}
        {label}
        {tooltipText && tooltipText.length !== 0 && (
          <Tooltip text={tooltipText} dataHtml={shouldInterpretTooltipHTML} />
        )}
        {link && (
          <Icon
            src={iconNewTabBlack}
            isClickable
            onClick={link.onClick}
            customStyle={link.customStyle}
          />
        )}
      </LabelContainer>
    );
  };

  useEffect(() => {
    const dropdownListElem = document.getElementById('dropdown-list');

    if (dropdownListElem && !pagination?.isLoading) {
      dropdownListElem.scroll(0, scrollValue);
    }

    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [pagination && pagination?.isLoading]);

  const renderLoadingDropdownList = () => {
    const arrayOfLoadingDropdownItems: JSX.Element[] = [];

    times(NUMBER_OF_LOADING_DROPDOWN_ITEMS_TO_DISPLAY, (index) =>
      arrayOfLoadingDropdownItems.push(
        <LoadingDropdownItem key={`loading-dropdown-item-${index}`} />
      )
    );

    return (
      <LoadingDropdownListContainer>
        {arrayOfLoadingDropdownItems.map(
          (loadingDropdownItem) => loadingDropdownItem
        )}
      </LoadingDropdownListContainer>
    );
  };

  const renderInputDropdown = () => {
    const inputText = getInputText();

    return (
      <InputContainer
        onClick={triggerDropdownList}
        isDisabled={isDisabled}
        isFocus={shouldDisplayDropdownList}
        error={isErrorState}
      >
        {iconSrc && <Icon style={iconCustomStyle} src={iconSrc} />}
        <Text
          iconSrc={iconSrc}
          isDisabled={isDisabled}
          isPlaceholder={!selectedItems.length}
          isFocus={shouldDisplayDropdownList}
          isValue={!!selectedItems.length}
        >
          {inputText}
        </Text>
        <Icon src={getInputCarretIcon()} />
      </InputContainer>
    );
  };

  const renderDropdownList = () => {
    if (pagination?.isLoading) {
      return (
        <DropdownListContainer
          customListStyle={customListStyle}
          largeDropdownList={largeDropdownList}
        >
          <SearchInputItem
            isLoading={isSearchLoading}
            largeDropdownList={largeDropdownList}
          >
            <Icon src={getInputSearchIcon()} isLoading={isSearchLoading} />
            <SearchInput
              isLoading={isSearchLoading}
              type="text"
              placeholder={searchPlaceholder}
              onChange={(e) => changeSearchValue(e.target.value)}
              ref={searchInputRef}
              onKeyDown={handleKeyDownSearchValue}
              disabled={isDisabled}
              autoFocus={shouldDisplayDropdownList}
            />
          </SearchInputItem>
          {renderLoadingDropdownList()}
        </DropdownListContainer>
      );
    }

    if (!items.length || !matchingItems || !matchingItems.length) {
      return (
        <DropdownListContainer
          customListStyle={customListStyle}
          largeDropdownList={largeDropdownList}
        >
          {(!!pagination ||
            (!!items.length &&
              shouldDisplaySearchInput() &&
              !isSearchDisabled)) && (
            <SearchInputItem largeDropdownList={largeDropdownList}>
              <Icon src={getInputSearchIcon()} />
              <SearchInput
                type="text"
                placeholder={searchPlaceholder}
                onChange={(e) => changeSearchValue(e.target.value)}
                ref={searchInputRef}
                disabled={isDisabled}
              />
              {dropdownSearchValue && (
                <Icon
                  src={closeIconBlack}
                  onClick={resetSearchValue}
                  isClickable
                />
              )}
            </SearchInputItem>
          )}
          <DropdownList
            largeDropdownList={largeDropdownList}
            customDropdownListStyle={customDropdownListStyle}
            id="dropdown-list"
            isSearchDisplay={!isSearchDisabled && shouldDisplaySearchInput()}
          >
            <DropdownItem isDisabled largeDropdownList={largeDropdownList}>
              {i18next.t('GENERAL_NO_RESULT')}
            </DropdownItem>
          </DropdownList>
          {!!button && (
            <DropdownButton
              onClick={() => button.handleClick()}
              disabled={button.isDisabled}
              isMultiSelect={!isUniqueSelection}
            >
              <Icon src={button.iconSrc} />
              {button.text}
            </DropdownButton>
          )}
        </DropdownListContainer>
      );
    }

    const matchingItemsSorted = sortItemsList(matchingItems);

    if (isUniqueSelection) {
      return (
        <DropdownListContainer
          customListStyle={customListStyle}
          largeDropdownList={largeDropdownList}
        >
          {!isSearchDisabled && shouldDisplaySearchInput() && (
            <SearchInputItem largeDropdownList={largeDropdownList}>
              <Icon src={getInputSearchIcon()} />
              <SearchInput
                type="text"
                placeholder={searchPlaceholder}
                onChange={(e) => changeSearchValue(e.target.value)}
                ref={searchInputRef}
                onKeyDown={handleKeyDownSearchValue}
                disabled={isDisabled}
                autoFocus={shouldDisplayDropdownList}
              />
              {dropdownSearchValue && (
                <Icon
                  src={closeIconBlack}
                  onClick={resetSearchValue}
                  isClickable
                />
              )}
            </SearchInputItem>
          )}
          {isListLoading
            ? renderLoadingDropdownList()
            : !!matchingItems.length && (
                <DropdownList
                  largeDropdownList={largeDropdownList}
                  customDropdownListStyle={customDropdownListStyle}
                  isSearchDisplay={
                    !isSearchDisabled && shouldDisplaySearchInput()
                  }
                  haveButton={!!button && isSearching}
                  id="dropdown-list"
                >
                  {matchingItemsSorted.map((item, idx) => {
                    return (
                      <DropdownItem
                        largeDropdownList={largeDropdownList}
                        key={`item-${item.id}-${idx}`}
                        onClick={() => selectItem(item)}
                        isDisabled={item.isDisabled}
                      >
                        {!!item.renderValue && item.renderValue()}
                        {!item.renderValue && (
                          <DropdownItemText
                            largeDropdownList={largeDropdownList}
                          >
                            {getDisplayValue(item)}
                          </DropdownItemText>
                        )}
                        {isSelected(selectedItems, item) && (
                          <Icon
                            src={checkIconBlack}
                            onClick={resetSearchValue}
                            isClickable
                          />
                        )}
                        {item.tags && item.tags.length > 0 && (
                          <DropdownItemTag>
                            {item.tags.join(', ')}
                          </DropdownItemTag>
                        )}
                      </DropdownItem>
                    );
                  })}
                  {pagination?.displayShowMoreResult && (
                    <DropdownItem
                      largeDropdownList={largeDropdownList}
                      isDisabled={isLoadingMoreResult}
                      key="item-show-more-results"
                      onClick={() => {
                        setIsLoadingMoreResult(true);
                        pagination?.handleFetchMoreData(
                          paginationDropdownSearchValue ||
                            TYPES_OF_DATA_TO_FETCH.LOAD_MORE_DATA
                        );
                      }}
                    >
                      <DropdownItemText
                        className="item-show-more-results-text"
                        isLoading={isLoadingMoreResult}
                        largeDropdownList={largeDropdownList}
                      >
                        {isLoadingMoreResult ? (
                          <>
                            <SpinnerImg src={SpinnerIcon} />
                            {i18next.t('GENERAL.SHOW_MORE_RESULTS')}
                          </>
                        ) : (
                          i18next.t('GENERAL.SHOW_MORE_RESULTS')
                        )}
                      </DropdownItemText>
                    </DropdownItem>
                  )}
                </DropdownList>
              )}
          {!!button && isSearching && (
            <DropdownButton
              onClick={() => button.handleClick()}
              disabled={button.isDisabled}
            >
              <Icon src={button.iconSrc} />
              {button.text}
            </DropdownButton>
          )}
        </DropdownListContainer>
      );
    }

    const isSearchDisplay = !isSearchDisabled && shouldDisplaySearchInput();

    return (
      <DropdownListContainer
        customListStyle={customListStyle}
        isSearchDisplay={isSearchDisplay}
        isMultiSelect
        largeDropdownList={largeDropdownList}
      >
        {isSearchDisplay && (
          <SearchInputItem
            isLoading={isSearchLoading}
            largeDropdownList={largeDropdownList}
          >
            <Icon src={getInputSearchIcon()} isLoading={isSearchLoading} />
            <SearchInput
              isLoading={isSearchLoading}
              type="text"
              placeholder={searchPlaceholder}
              onChange={(e) => changeSearchValue(e.target.value)}
              ref={searchInputRef}
              disabled={isDisabled}
              autoFocus={shouldDisplayDropdownList}
            />
            {dropdownSearchValue && (
              <Icon
                src={closeIconBlack}
                onClick={resetSearchValue}
                isClickable
              />
            )}
          </SearchInputItem>
        )}
        {isListLoading
          ? renderLoadingDropdownList()
          : !!matchingItems.length && (
              <DropdownList
                largeDropdownList={largeDropdownList}
                isSearchDisplay={isSearchDisplay}
                isMultiSelect
                haveButton={!!button && isSearching}
                id="dropdown-list"
                customDropdownListStyle={customDropdownListStyle}
              >
                <DropdownItem
                  onClick={selectAllMatchingItems}
                  largeDropdownList={largeDropdownList}
                  isDisabled={!!maxSelection}
                >
                  <CheckboxContainer>
                    <Checkbox
                      noSize
                      shape="square"
                      isChecked={isSelectAllChecked()}
                      isDisabled={!!maxSelection}
                    />
                  </CheckboxContainer>
                  <DropdownItemText largeDropdownList={largeDropdownList}>
                    {!dropdownSearchValue
                      ? i18next.t('COMPONENT_DROPDOWN_SELECT_ALL')
                      : i18next.t('COMPONENT_DROPDOWN_SELECT_ALL_SEARCH')}
                  </DropdownItemText>
                </DropdownItem>
                {matchingItemsSorted.map((item, idx) => {
                  return (
                    <DropdownItem
                      largeDropdownList={largeDropdownList}
                      key={`item-${item.id}-${idx}`}
                      onClick={() => selectItem(item)}
                      isDisabled={isDisabledItem(item)}
                      isSearchDisplay={isSearchDisplay}
                      isMultiSelect
                    >
                      <CheckboxContainer>
                        <Checkbox
                          noSize
                          shape="square"
                          isChecked={isSelected(tmpSelectedItems, item)}
                          isDisabled={isDisabledItem(item)}
                        />
                      </CheckboxContainer>
                      {!!item.renderValue && item.renderValue()}
                      {!item.renderValue && (
                        <DropdownItemText largeDropdownList={largeDropdownList}>
                          {getDisplayValue(item)}
                        </DropdownItemText>
                      )}
                      {item.tags && item.tags.length > 0 && (
                        <DropdownItemTag>
                          {item.tags.join(', ')}
                        </DropdownItemTag>
                      )}
                    </DropdownItem>
                  );
                })}
                {pagination?.displayShowMoreResult && (
                  <DropdownItem
                    largeDropdownList={largeDropdownList}
                    isDisabled={isLoadingMoreResult}
                    key="item-show-more-results"
                    onClick={() => {
                      setIsLoadingMoreResult(true);
                      pagination?.handleFetchMoreData(
                        paginationDropdownSearchValue ||
                          TYPES_OF_DATA_TO_FETCH.LOAD_MORE_DATA
                      );
                    }}
                  >
                    <DropdownItemText
                      className="item-show-more-results-text"
                      isLoading={isLoadingMoreResult}
                      largeDropdownList={largeDropdownList}
                    >
                      {isLoadingMoreResult ? (
                        <>
                          <SpinnerImg src={SpinnerIcon} />
                          {i18next.t('GENERAL.SHOW_MORE_RESULTS')}
                        </>
                      ) : (
                        i18next.t('GENERAL.SHOW_MORE_RESULTS')
                      )}
                    </DropdownItemText>
                  </DropdownItem>
                )}
              </DropdownList>
            )}
        {!!button && isSearching && (
          <DropdownButton
            onClick={() => button.handleClick()}
            disabled={button.isDisabled}
            isMultiSelect
          >
            <Icon src={button.iconSrc} />
            {button.text}
          </DropdownButton>
        )}
        <MultiselectValidationButton
          onClick={validateSelection}
          disabled={isValidationDisabled()}
          haveButton={!!button}
        >
          <Icon src={checkIconWhite} />
          {i18next.t('GENERAL_APPLY')}
        </MultiselectValidationButton>
      </DropdownListContainer>
    );
  };

  return (
    <ThemeProvider theme={updatedTheme}>
      <Container
        style={customStyle}
        width={width}
        height={height}
        ref={wrapperRef}
      >
        {label && renderDropdownLabel()}
        {renderInputDropdown()}
        {shouldDisplayDropdownList && renderDropdownList()}
      </Container>
    </ThemeProvider>
  );
};

Dropdown.propTypes = {
  // eslint-disable-next-line react/forbid-prop-types
  theme: PropTypes.objectOf(PropTypes.any),
  width: PropTypes.string,
  height: PropTypes.string,
  customStyle: PropTypes.shape({
    zIndex: PropTypes.string,
  }),
  items: PropTypes.arrayOf(
    PropTypes.shape({
      renderValue: PropTypes.func,
      value: PropTypes.string.isRequired,
      name: PropTypes.string,
      id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
      isDisabled: PropTypes.bool,
      tags: PropTypes.arrayOf(PropTypes.string),
    })
  ),
  selectedItems: PropTypes.arrayOf(
    PropTypes.shape({
      renderValue: PropTypes.func,
      value: PropTypes.string.isRequired,
      name: PropTypes.string,
    })
  ),
  placeholder: PropTypes.string,
  label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  isDisabled: PropTypes.bool,
  isRequired: PropTypes.bool,
  isSearchDisabled: PropTypes.bool,
  isUniqueSelection: PropTypes.bool,
  onSelectionChange: PropTypes.func,
  onTriggerDropdownList: PropTypes.func,
  iconSrc: PropTypes.string,
  iconCustomStyle: PropTypes.shape({
    width: PropTypes.string,
    height: PropTypes.string,
  }),
  searchPlaceholder: PropTypes.string,
  button: PropTypes.shape({
    text: PropTypes.string.isRequired,
    handleClick: PropTypes.func.isRequired,
    iconSrc: PropTypes.string,
    isDisable: PropTypes.bool,
  }),
  sortBy: PropTypes.func,
  // eslint-disable-next-line react/forbid-prop-types
  labelStyle: PropTypes.objectOf(PropTypes.any),
  // eslint-disable-next-line react/forbid-prop-types
  customListStyle: PropTypes.objectOf(PropTypes.any),
  tooltipText: PropTypes.string,
  shouldInterpretTooltipHTML: PropTypes.bool,
  searchDebounceTimeInMs: PropTypes.number,
  isErrorState: PropTypes.bool,
  // eslint-disable-next-line react/forbid-prop-types
  customDropdownListStyle: PropTypes.objectOf(PropTypes.any),
  pagination: PropTypes.shape({
    handleFetchMoreData: PropTypes.func.isRequired,
    displayShowMoreResult: PropTypes.bool.isRequired,
    isLoading: PropTypes.bool.isRequired,
  }),
  languageCode: PropTypes.string,
  displayName: PropTypes.bool,
  largeDropdownList: PropTypes.bool,
  maxSelection: PropTypes.number,
};

Dropdown.defaultProps = {
  theme: null,
  items: [],
  iconSrc: null,
  width: '240px',
  height: '40px',
  customStyle: {},
  placeholder: i18next.t('COMPONENT_DROPDOWN_INPUT_PLACEHOLDER'),
  label: null,
  selectedItems: [],
  isSearchDisabled: false,
  isUniqueSelection: true,
  iconCustomStyle: { width: '16px', height: '16px' },
  isDisabled: false,
  isRequired: false,
  isErrorState: false,
  searchPlaceholder: i18next.t('COMPONENT_DROPDOWN_SEARCH'),
  button: null,
  labelStyle: {},
  customListStyle: {},
  tooltipText: null,
  shouldInterpretTooltipHTML: false,
  sortBy: (itemsList: Item[]): Item[] =>
    lodashSortBy(itemsList, (item) => {
      if (typeof item.value === 'string') {
        return item.value.toLowerCase();
      }

      return 0;
    }),
  onTriggerDropdownList: null,
  searchDebounceTimeInMs: 300,
  onSelectionChange: () => true,
  pagination: null,
  customDropdownListStyle: {},
  languageCode: 'fr',
  displayName: false,
  largeDropdownList: false,
  maxSelection: null,
};

export default Dropdown;
