import React, {
  cloneElement,
  FunctionComponent,
  ReactElement,
  useEffect,
  useMemo,
  useState,
} from 'react';
import { observer } from 'mobx-react-lite';
import { Box, Divider, TableToolbar } from '@wix/design-system';
import { FiltersMap } from '@wix/bex-core';
import { CollectionProvider } from '../CollectionContext';
import { ToolbarCollectionState } from '../../state';
import { PartialFunctionComponent } from '../PartialFunctionComponent';
import type {
  CollectionSearchElement,
  MultiLevelSortingElement,
} from '../assertComponentType';
import { assertComponentType } from '../assertComponentType';
import { ToolbarItemBox } from '../ToolbarItemBox';
import { classes, st } from './CollectionToolbar.st.css.js';
import { InitialLoadingConditional } from '../InitialLoadingConditional';
import {
  ToolbarBaseProps,
  ToolbarCollectionBaseProps,
} from '../ToolbarCollection';
import { useCollectionToolbarSyncedProps } from './useCollectionToolbarSyncedProps';
import { useIsCollectionToolbarExists } from './useIsCollectionToolbarExists';
import { CollectionToolbarActionsToolbarItemsGroup } from './CollectionToolbarActionsToolbarItemsGroup';
import { MoreActions } from '../MoreActions';
import { CollectionToolbarSkeletonItem } from './CollectionToolbarSkeletonItem';
import { useIsMobile } from '../../hooks/useIsMobile';
import { isValidElement } from '../isValidElement';
import { CollectionSearch } from '../CollectionSearch';
import { CollectionToolbarLeftGroup } from './CollectionToolbarLeftGroup';
import { CollectionToolbarActionsGroupResponsiveLayout } from './CollectionToolbarActionsGroupResponsiveLayout';
import { getToolbarMode } from './toolbarModeUtils';
import { TableGridSwitchButtonProps } from '../TableGridSwitchButton/TableGridSwitchButton';

export interface CollectionToolbarProps<T, F extends FiltersMap> {
  state: ToolbarCollectionState<T, F>;
  title?: ToolbarCollectionBaseProps<T, F>['title'];
  tabs?: ToolbarCollectionBaseProps<T, F>['tabs'];
  customColumns?: ToolbarCollectionBaseProps<T, F>['customColumns'];
  multiLevelSorting?: MultiLevelSortingElement;
  views?: ToolbarCollectionBaseProps<T, F>['views'];
  search?: ToolbarBaseProps['search'];
  dataHook?: string;
  filters?: ToolbarCollectionBaseProps<T, F>['filters'];
  tableGridSwitchButton?: ToolbarCollectionBaseProps<
    T,
    F
  >['tableGridSwitchButton'];
  exportButton?: ToolbarCollectionBaseProps<T, F>['exportButton'];
  importButton?: ToolbarCollectionBaseProps<T, F>['importButton'];
  primaryActionButton?: ToolbarCollectionBaseProps<T, F>['primaryActionButton'];
  dragAndDropReorderModeToolbar?: ToolbarCollectionBaseProps<
    T,
    F
  >['dragAndDropReorderModeToolbar'];
  secondaryActions?: ToolbarCollectionBaseProps<T, F>['secondaryActions'];
  moreActions?: ToolbarCollectionBaseProps<T, F>['moreActions'];
}

function _CollectionToolbar<T, F extends FiltersMap>(
  props: CollectionToolbarProps<T, F>,
) {
  const {
    state,
    search = true,
    title,
    tabs,
    customColumns,
    multiLevelSorting,
    views,
    dataHook,
    filters: filtersProp,
    tableGridSwitchButton,
    exportButton,
    importButton,
    dragAndDropReorderModeToolbar,
    primaryActionButton,
    secondaryActions,
    moreActions,
  } = props;

  const isMobile = useIsMobile();

  const hasOtherToolbarFeatures = useIsCollectionToolbarExists(props, {
    excludeSearch: true,
    isMobile,
  });
  const searchIsExpandable = isMobile ? hasOtherToolbarFeatures : undefined;

  assertComponentType(
    primaryActionButton,
    'PrimaryActionButton',
    'PrimaryActionButton',
  );
  const {
    collection,
    featuredComponents,
    toolbar: { responsive },
    container: { isPanelLayout },
  } = state;

  const addDataHookToMoreActions = () => {
    return (
      <MoreActions dataHook="toolbar-more-actions" {...moreActions!.props} />
    );
  };

  const searchElement = isPanelLayout ? undefined : isValidElement(search) ? (
    cloneElement(search as CollectionSearchElement, {
      expandable:
        searchIsExpandable ??
        (search as CollectionSearchElement).props.expandable,
    })
  ) : search ? (
    <CollectionSearch size="small" expandable={searchIsExpandable} />
  ) : (
    search
  );

  const MoreFiltersButton = featuredComponents.moreFiltersButton
    .value as PartialFunctionComponent as FunctionComponent | null;

  const viewsToolbarItem = isPanelLayout
    ? undefined
    : views && (
        <ToolbarItemBox dataHook="collection-table-toolbar-views-item">
          {views}
        </ToolbarItemBox>
      );

  const CollectionToolbarFilters =
    state.tagsCollectionState?.components.CollectionToolbarFilters ||
    state.collectionDataExtension?.components.CollectionToolbarFilters;

  const filtersElement = useMemo(() => {
    if (!state.container.initTask.status.isSuccess) {
      return;
    }

    if (isMobile) {
      return undefined;
    }

    if (filtersProp) {
      return filtersProp;
    }
    const featureFilters = [
      ...(state.collectionDataExtension?.buildCustomFieldFilters() || []),
      state.tagsCollectionState?.buildTagsFilterWrapper(),
    ].filter(Boolean);

    return (
      filtersProp ??
      (CollectionToolbarFilters && (
        <CollectionToolbarFilters inline={0}>
          {featureFilters}
        </CollectionToolbarFilters>
      ))
    );
  }, [filtersProp, isMobile, state.container.initTask.status]);

  let left: ReactElement | undefined;

  if (tabs) {
    left = (
      <ToolbarItemBox removeStartPadding expandable layout="button">
        {tabs}
      </ToolbarItemBox>
    );
  } else if (title && !isMobile) {
    left = title;
  }

  useCollectionToolbarSyncedProps({
    left,
    filtersElement,
    viewsToolbarItem,
    state,
  });

  /* checking if something is rendered in the .left TableToolbar.ItemGroup (not empty) */
  const [rendersStart, setRendersStart] = useState<boolean>();

  useEffect(() => {
    setRendersStart(
      !!left ||
        !!viewsToolbarItem ||
        (state.toolbarFiltersState?.totalInlineFilters.value !== undefined &&
          state.toolbarFiltersState?.totalInlineFilters.value !== null &&
          state.toolbarFiltersState?.totalInlineFilters.value > 0),
    );
  }, [left, viewsToolbarItem, state.toolbarFiltersStateInitialized]);

  const isLayoutToggleRedesignEnabled =
    state.container.internalExperiments?.enabled(
      'specs.cairo.layout-toggle.redesign',
    );

  const shouldAddDivider =
    !isLayoutToggleRedesignEnabled &&
    tableGridSwitchButton &&
    (searchElement || MoreFiltersButton);

  const analyticsCustomColumnsDiscoverability =
    state.container.experiments?.get(
      'specs.analytics.CustomColumnsWithLabelAndNewIcon',
    );

  const showCustomColumnsOnTheLeft =
    analyticsCustomColumnsDiscoverability === 'b' ||
    analyticsCustomColumnsDiscoverability === 'c';

  const immidiatelyInteractWithToolbarsEnabled =
    state.container.internalExperiments?.enabled(
      'specs.cairo.ImmidiatelyInteractWithToolbars',
    );

  const CollectionToolbarActionsGroup =
    isMobile || responsive.responsiveDisabled
      ? CollectionToolbarActionsToolbarItemsGroup
      : CollectionToolbarActionsGroupResponsiveLayout;

  const responsiveMode = getToolbarMode({
    isDisabled: responsive.responsiveDisabled,
    hasTabs: !!tabs,
    hasTitle: !!left && !viewsToolbarItem,
    hasViews: !!viewsToolbarItem,
  });

  const toolbarElement = (
    <>
      <TableToolbar.ItemGroup
        position="start"
        className={st(classes.left, {
          expandable: !!tabs,
          title: responsiveMode === 'title',
        })}
        dataHook="collection-table-toolbar-filters"
      >
        <CollectionToolbarLeftGroup
          state={state}
          left={left}
          viewsToolbarItem={viewsToolbarItem}
          filtersElement={filtersElement}
          mode={responsiveMode}
        />
      </TableToolbar.ItemGroup>

      <TableToolbar.ItemGroup
        position={isMobile ? undefined : 'end'}
        className={st(
          classes.right,
          {},
          ...[rendersStart ? undefined : classes.fullWidth],
        )}
      >
        <CollectionToolbarActionsGroup
          state={state}
          viewsToolbarItem={viewsToolbarItem}
          filtersElement={filtersElement}
          MoreFiltersButton={MoreFiltersButton}
          multiLevelSorting={multiLevelSorting}
          customColumns={isMobile || isPanelLayout ? undefined : customColumns}
          exportButton={exportButton}
          importButton={importButton}
          search={searchElement}
          showCustomColumnsOnTheLeft={showCustomColumnsOnTheLeft}
          left={left}
          hasTabs={!!tabs}
          tableGridSwitchButton={
            isLayoutToggleRedesignEnabled ? tableGridSwitchButton : undefined
          }
          viewTypeState={
            isLayoutToggleRedesignEnabled
              ? (
                  tableGridSwitchButton as ReactElement<TableGridSwitchButtonProps>
                )?.props?.state
              : undefined
          }
        />

        {primaryActionButton && (
          <TableToolbar.Item>{primaryActionButton}</TableToolbar.Item>
        )}
        {moreActions && (
          <TableToolbar.Item>{addDataHookToMoreActions()}</TableToolbar.Item>
        )}
        {secondaryActions && (
          <TableToolbar.Item>{secondaryActions}</TableToolbar.Item>
        )}
        {shouldAddDivider && (
          <Box alignSelf="stretch" paddingLeft="SP2">
            <Divider
              direction="vertical"
              dataHook="collection-table--grid-switch--divider"
            />
          </Box>
        )}
        {!isLayoutToggleRedesignEnabled && tableGridSwitchButton && (
          <TableToolbar.Item>{tableGridSwitchButton}</TableToolbar.Item>
        )}
      </TableToolbar.ItemGroup>
    </>
  );

  const toolbarWithSkeleton = (
    <InitialLoadingConditional
      state={state}
      loadingElement={
        <CollectionToolbarSkeletonItem
          dataHook="toolbar-skeleton"
          width="100px"
        />
      }
      hideLoadingElement={immidiatelyInteractWithToolbarsEnabled}
    >
      {toolbarElement}
    </InitialLoadingConditional>
  );

  return (
    <CollectionProvider value={collection}>
      <Box direction="vertical" dataHook={dataHook}>
        <Box
          minHeight={
            isPanelLayout ? '48px' : title?.props.subtitle ? '78px' : '60px'
          }
        >
          {state.isReorderModeToolbarVisible ? (
            dragAndDropReorderModeToolbar
          ) : (
            <TableToolbar
              removeVerticalPadding
              className={st(classes.root, {
                views: !responsive.responsiveDisabled,
                mobile: isMobile,
                responsiveMode,
              })}
              dataHook="collection-table-toolbar"
            >
              {toolbarWithSkeleton}
            </TableToolbar>
          )}
        </Box>
      </Box>
    </CollectionProvider>
  );
}

export const CollectionToolbar = observer(_CollectionToolbar);
