import React, { useEffect, useState } from 'react';
import {
  CollectionFilterState,
  DropdownCollectionFilterState,
} from '../../state';
import { CollectionState, FiltersMap, TextOverflowState } from '@wix/bex-core';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { observer } from 'mobx-react-lite';
import {
  KeyedItemOption,
  MultiSelectCheckboxFilterBase,
  MultiSelectCheckboxFilterBaseProps,
} from '../MultiSelectCheckboxFilterBase';
import { ListItem } from '../../hooks';
import { InputOverflow } from '../InputOverflow';
import {
  useFilterToolbarState,
  useDropdownTranslationContext,
} from '../../providers';
import {
  useCollectionFilterInitialFetchTiming,
  CollectionFilterInitialFetchTimingProps,
} from '../../hooks/useCollectionFilterInitialFetchTiming';
import { useFilterCollectionStates } from '../../hooks/useFilterCollectionStates';
import { useCollectionOptions } from '../../hooks/useCollectionOptions';
import { useDropdownPlaceholder } from '../../hooks/useDropdownPlaceholder';

export interface CollectionMultiSelectCheckboxProps<
  V,
  F extends FiltersMap = FiltersMap,
> extends Omit<
      MultiSelectCheckboxFilterBaseProps<V>,
      'options' | 'dropdownSelect'
    >,
    CollectionFilterInitialFetchTimingProps {
  /**
   * A collection state object to fetch the dropdown items.<br>
   * A collection created using [useFilterCollection](./?path=/story/features-filter-hooks--usefiltercollection) or [useStaticListFilterCollection](./?path=/story/features-filter-hooks--usestaticlistfiltercollection)
   * @external
   */
  collection: CollectionState<V, F>;
  /**
   * A function that returns a [ListItemSelectProps](https://www.docs.wixdesignsystem.com/?path=/story/components-form-dropdownlistitems--listitemselect) (Optional)
   */
  renderItem?: (item: V, index: number) => ListItem;
  /**
   * The maximum number of items that can be selected. Once reached, every
   * unselected option becomes disabled (already-selected options stay
   * deselectable). When undefined, selection is unbounded.
   *
   * Read once on mount — later changes to this prop are ignored. (Optional)
   */
  maxSelected?: number;
}

function _CollectionMultiSelectCheckbox<V, F extends FiltersMap = FiltersMap>(
  props: CollectionMultiSelectCheckboxProps<V, F>,
) {
  const {
    filter,
    collection,
    renderItem,
    onSelect,
    onClose,
    onOptionsShow,
    onDeselect,
    placeholder: placeholderProp,
    maxSelected,
    ...rest
  } = props;

  const container = useWixPatternsContainer();
  const toolbar = useFilterToolbarState();

  const { translate } = useDropdownTranslationContext();

  const [collectionFilter] = useState(
    () =>
      new CollectionFilterState({
        collection,
        filter,
      }),
  );

  const [dropdownCollectionFilterState] = useState(
    () =>
      new DropdownCollectionFilterState<V, F>({
        resetOnClose: false,
        collectionFilter,
        container,
        toolbar,
        maxSelected,
      }),
  );

  const {
    dropdownSelect,
    init,
    inputState,
    shouldShowPlaceholder,
    inputValue,
  } = dropdownCollectionFilterState;
  const { disableEditing } = inputState;

  const {
    select: { selectedKeys, selectedValues },
  } = dropdownSelect;

  const [textOverflowState] = useState(
    () =>
      new TextOverflowState({
        observable: () => dropdownSelect.select.selectedValues,
      }),
  );
  const { isOverflow } = textOverflowState;
  const { fetchedLastPage } = collection;
  const { fixedFooter, showInitialLoader } = useFilterCollectionStates({
    collection,
    fixedFooter: rest.fixedFooter,
  });

  const { skipInitialFetch, onFocus } =
    useCollectionFilterInitialFetchTiming(props);

  useEffect(() => init({ skipInitialFetch }), []);

  const { selectedValuesText, placeholder } = useDropdownPlaceholder({
    dropdownSelect,
    filter,
    shouldShowPlaceholder,
    isOverflow,
    placeholderProp,
  });
  const { options } = useCollectionOptions({
    collection,
    dropdownCollectionFilterState,
    renderItem,
    filter,
  });

  return (
    <MultiSelectCheckboxFilterBase
      {...rest}
      fixedFooter={fixedFooter}
      infiniteScroll
      filter={filter}
      dropdownSelect={dropdownSelect}
      options={options}
      selectedOptions={selectedKeys}
      hasMore={!showInitialLoader && !fetchedLastPage}
      loadMore={collection.fetchNextPageIfNeeded}
      onClose={() => {
        if (!dropdownSelect.hasPendingFilter) {
          dropdownSelect.closeAndChangeSelectedItems();
        } else {
          dropdownSelect.close();
        }
        inputState.onBlur();
        onClose?.();
      }}
      onSelect={(id, option) => {
        const { keyedItem } = option as KeyedItemOption<V>;
        dropdownSelect.set(keyedItem);
        onSelect?.(id, option);
      }}
      onDeselect={(id, option) => {
        const { keyedItem } = option as KeyedItemOption<V>;
        dropdownSelect.delete(keyedItem);
        onDeselect?.(id, option);
      }}
      value={inputValue}
      onFocus={() => {
        inputState.onFocus();
        onFocus();
      }}
      onBlur={() => {
        inputState.onBlur();
      }}
      onChange={(e) => {
        collection.search(e.target.value, { clearResult: true });
      }}
      onOptionsShow={() => {
        dropdownCollectionFilterState.onOptionsShow();
        inputState.onOptionsShow();
        onOptionsShow?.();
      }}
      onKeyDown={(e) => {
        if (e.nativeEvent.code === 'Tab') {
          inputState.onTabKeyDown();
        }
      }}
      onClickOutside={(e) => {
        props.onClickOutside?.(e);
        inputState.onClickOutside();
      }}
      onClear={() => {
        inputState.onBlur();
        collection.clearSearch();
      }}
      disableEditing={disableEditing}
      placeholder={placeholder}
      clearButton={!disableEditing}
      clearButtonTooltipContent={translate('clearButtonTooltip')}
      focusOnClearClick
      inputElement={
        <InputOverflow
          selected={selectedValues.length > 0}
          focused={inputState.isFocused}
          text={selectedValuesText}
          state={textOverflowState}
        />
      }
    />
  );
}

export const CollectionMultiSelectCheckbox = observer(
  _CollectionMultiSelectCheckbox,
);
