import React, {
  Fragment,
  ReactNode,
  useEffect,
  useMemo,
  useState,
} from 'react';
import { Box } from '@wix/design-system';
import { FilterElement } from './filterElement';
import { useFiltersLayout } from './useFiltersLayout';
import { useToolbarCollectionContext } from '../ToolbarCollectionContext';
import { AppliedFiltersTagList } from '../AppliedFiltersTagList';
import { observer } from 'mobx-react-lite';
import { ToolbarItemBox } from '../ToolbarItemBox';
import { AppliedFiltersTagListState } from '../AppliedFiltersTagList/AppliedFiltersTagListState';
import { CollectionToolbarFiltersState } from './CollectionToolbarFiltersState';
import { getFieldTypeIcon } from '../../utils/fieldTypePrefixIcons';
import { CollectionFilter } from '../CollectionFilter';
import { FiltersPanelSidePanelEntry } from './FiltersPanelSidePanelEntry';
import { MoreFiltersCTA } from '../MoreFiltersCTA';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { useFiltersSyncProps } from './useFiltersSyncProps';

export interface CollectionToolbarFiltersProps {
  /**
   * Number of filter controls to be rendered inside the table toolbar
   */
  inline?: 0 | 1 | 2 | 3;
  /**
   * A flag that indicates whether Patterns should use a new filters layout our not.
   */
  useNewFilters?: true;
  maxInlineFilters?: number;
  maxInlineLabels?: number;
  /**
   * Title of the filters panel
   * @external
   */
  panelTitle?: string | ReactNode;
  /**
   * `React` children elements, that must accept [FilterProps](./?path=/story/features-filter-props--filterprops), such as:
   * - [MultiSelectCheckboxFilter](./?path=/story/features-filter-components--multiselectcheckboxfilter)
   * - [Custom Filters](./?path=/story/features-filter-factories--customfilter)
   * @external
   */
  children:
    | (FilterElement | undefined | boolean)
    | (FilterElement | undefined | boolean)[];
  onPanelClearButtonClicked?: () => unknown;
  onSearchAppliedFilterTagRemove?: (item: string) => unknown;
  onSubToolbarClearButtonClicked?: () => unknown;
  hideAppliedFiltersTagList?: boolean;
}

function _CollectionToolbarFilters(props: CollectionToolbarFiltersProps) {
  const {
    children,
    inline = 2,
    maxInlineFilters,
    maxInlineLabels,
    panelTitle,
    onPanelClearButtonClicked,
    onSearchAppliedFilterTagRemove,
    onSubToolbarClearButtonClicked,
    hideAppliedFiltersTagList,
    useNewFilters,
  } = props;

  const childrenArr = useFiltersSyncProps(children);

  const state = useToolbarCollectionContext();

  const [toolbarFiltersState] = useState(() => {
    state.toolbarFiltersState ??= new CollectionToolbarFiltersState({
      toolbar: state,
    });
    state.setToolbarFiltersStateInitialized(true);
    return state.toolbarFiltersState;
  });

  useEffect(() => {
    state.panels.registerSidePanel('filters', FiltersPanelSidePanelEntry);
  }, []);

  useEffect(() => {
    toolbarFiltersState.onClearButtonClicked = onPanelClearButtonClicked;
  }, [onPanelClearButtonClicked]);

  const forceShowSidePanel = useMemo(
    () =>
      !!childrenArr.slice(0, inline).find((filter) => {
        return (
          filter.type.displayName &&
          [
            'DateRangeFilter',
            'MultiSelectCollectionFilter',
            'RadioGroupFilter',
            'MultiInlineCheckboxFilter',
          ].includes(filter.type.displayName)
        );
      }),
    [childrenArr],
  );

  const { viewsProps, collection } = state;

  const customInlineElements = viewsProps ? 1 : 0;

  const { showFiltersPanelButton, totalInlineFilters, showLabels } =
    useFiltersLayout({
      useNewFilters,
      filters: childrenArr.length,
      totalFilters: childrenArr.length + customInlineElements,
      inline,
      maxInlineFilters,
      maxInlineLabels,
      customInlineElements,
      forceShowSidePanel,
    });

  useEffect(() => {
    toolbarFiltersState.panelTitle.set(panelTitle);
  }, [panelTitle]);

  useEffect(() => {
    toolbarFiltersState.totalInlineFilters.set(totalInlineFilters);
  }, [totalInlineFilters]);

  useEffect(() => {
    toolbarFiltersState.filterElements.set(childrenArr);
  }, [childrenArr]);

  const container = useWixPatternsContainer();
  const { filters } = collection;

  const filtersProps = useMemo(() => {
    // share essential filter props globally
    return [
      ...childrenArr.map(({ props: filterChildProps, type }) => {
        const {
          filter,
          onAppliedFilterTagRemove,
          renderToolbarTag,
          toolbarTagProps,
          accordionItemProps,
        } = filterChildProps;

        return {
          filter,
          onAppliedFilterTagRemove,
          toolbarTagProps,
          accordionItemProps,
          renderToolbarTag:
            renderToolbarTag ??
            type.renderPresetToolbarTag?.(container, {
              filterProps: filterChildProps,
            }),
        };
      }),
      {
        filter: filters.search,
        onAppliedFilterTagRemove: onSearchAppliedFilterTagRemove,
      },
    ];
  }, [
    childrenArr.length,
    ...childrenArr.map(({ props: { filter } }) => filter),
  ]);

  useEffect(() => {
    state.setFilterTagsPropsIfChanged(filtersProps);

    return () => {
      state.setFilterTagsPropsIfChanged(null);
    };
  }, [filtersProps]);

  useEffect(() => {
    if (showFiltersPanelButton) {
      state.featuredComponents.moreFiltersButton.set(() => <MoreFiltersCTA />);

      return () => {
        state.featuredComponents.moreFiltersButton.set(null);
      };
    }

    state.featuredComponents.moreFiltersButton.set(null);

    return;
  }, [showFiltersPanelButton]);

  const [tagListState] = useState(
    () =>
      new AppliedFiltersTagListState({
        table: state,
      }),
  );

  useEffect(() => {
    const disposers = [tagListState.init()];

    if (hideAppliedFiltersTagList) {
      state.featuredComponents.appliedFiltersTagList.set(null);
    } else {
      state.featuredComponents.appliedFiltersTagList.set({
        state: tagListState,
        component: () => (
          <AppliedFiltersTagList
            state={tagListState}
            onClearButtonClicked={onSubToolbarClearButtonClicked}
          />
        ),
      });
    }

    return () => {
      disposers.forEach((d) => d());
      state.featuredComponents.appliedFiltersTagList.set(null);
    };
  }, [hideAppliedFiltersTagList]);

  const showFieldTypeIcons = state.showFieldTypeIcons;

  return (
    // workaround to support bad enzyme version not detecting this as a valid fragment component
    // https://wix.slack.com/archives/C02K83200PL/p1671962461443749
    <Fragment key="toolbar-items">
      {childrenArr.slice(0, totalInlineFilters).map((element, index) => {
        const { props: filterProps } = element;
        const toolbarLabel = filterProps.toolbarItemProps?.label;
        let label: React.ReactNode = showLabels && toolbarLabel;
        if (showFieldTypeIcons && showLabels && toolbarLabel) {
          const toolbarIcon = getFieldTypeIcon({ fieldType: filterProps.fieldType, size: 'medium' });
          label = <Box gap="SP1" verticalAlign="middle">{toolbarIcon}{toolbarLabel}</Box>;
        }

        return (
          <ToolbarItemBox
            key={index}
            layout={filterProps.layout}
            dataHook={`toolbar-item-filter-${index}`}
            label={label}
          >
            {filterProps.filter ? (
              <CollectionFilter
                filter={filterProps.filter}
                state={toolbarFiltersState}
              >
                {element}
              </CollectionFilter>
            ) : (
              element
            )}
          </ToolbarItemBox>
        );
      })}
    </Fragment>
  );
}

export const CollectionToolbarFilters = observer(_CollectionToolbarFilters);
