import React, { ComponentType, useEffect, useState } from 'react';
import { FiltersMap } from '@wix/bex-core';
import { observer } from 'mobx-react-lite';
import {
  CollectionTableWSRTable,
  CollectionTableWSRTableBaseProps,
  CollectionTableWSRTableProps,
} from '../CollectionTable/CollectionTableWSRTable';
import { CollectionTableActionCellProps } from '../CollectionTable/CollectionTableBaseCommonProps';
import { NestedTableItem, NestedTableState } from '../../state';
import { NestedTableFlatDataItem } from '../../state/NestedTableState/NestedTableFlatModeSectionState';
import { NestedTableContent } from './NestedTableContent';
import { TopNotificationBasicRenderProp } from '../TableTopNotification';
import { useToolbarCollectionSyncProps } from '../ToolbarCollection/useToolbarCollectionSyncProps';
import { useModeTableProps } from './useModeTableProps';
import { runInAction } from 'mobx';
import { QuerySearch } from '../QuerySearch';
import { MultiCollectionSupportProvider } from '../MultiCollectionSupportProvider';
import { TablePlaceholderStates } from '../TablePlaceholderStates/TablePlaceholderStates';
import { NestedTableDragAndDrop } from '../NestedTableDragAndDrop/NestedTableDragAndDrop';
import { getVirtualTableProps } from '../Table/getVirtualTableProps';
import { CollectionToolbarFiltersElement } from '../assertComponentType';

export interface NestedTableWSRTableBaseProps<
  C extends string,
  T,
  F extends FiltersMap,
> extends Omit<
      CollectionTableWSRTableBaseProps<
        NestedTableItem<C, any, any> | NestedTableFlatDataItem<C, any, any>,
        T,
        F
      >,
      'actionCell' | 'sticky' | 'selectionDisabled' | 'topNotification'
    >,
    CollectionTableActionCellProps<T, F> {}

export interface NestedTableWSRTableProps<
  C extends string,
  T,
  F extends FiltersMap,
> extends NestedTableWSRTableBaseProps<C, T, F> {
  dataHook?: string;
  state: NestedTableState<C>;
  topNotification?: TopNotificationBasicRenderProp;
  rowHeight?: number;
  estimatedRowHeight?: number;
  dragAndDrop?: typeof NestedTableDragAndDrop;
  filters?: CollectionToolbarFiltersElement;
}

function _NestedTableWSRTable<C extends string, T, F extends FiltersMap>(
  props: NestedTableWSRTableProps<C, T, F>,
) {
  const {
    state: wrapperState,
    renderError,
    errorState = renderError &&
      (((err, { isOnline, retry }) =>
        renderError?.({
          err,
          isOnline,
          retry,
        })) as NestedTableWSRTableProps<C, T, F>['errorState']),
    multiLevelSorting,
    actionCell,
    actionCellWidth,
    actionCellProps,
    filters,
    emptyState,
    noResultsState,
    showTitleBar = !wrapperState.container.isPanelLayout,
    horizontalScroll = true,
    rowHeight,
    estimatedRowHeight,
    rowVerticalPadding = 'tiny',
    dragAndDrop,
    dragAndDropBulkSubmit,
    dragAndDropSubmit,
    dragAndDropCancel,
    dragAndDropReorderModeToolbar,
    dragAndDropCategories,
    search = true,
    tabs,
    ...rest
  } = props;
  const { toolbar, query } = wrapperState;

  useState(() => {
    dragAndDrop?.setStateObject({
      state: wrapperState,
    });
  });

  useToolbarCollectionSyncProps({
    ...props,
    state: toolbar,
    isUsingDragAndDrop: false,
    isUsingBulkActionsToolbar: false,
    isUsingHorizontalScroll: true,
    isUsingFolders: false,
    isUsingTableVirtualization: true,
  });

  const Table = CollectionTableWSRTable as ComponentType<
    CollectionTableWSRTableProps<any, T, F>
  >;

  const { state, key, BodyElementType, TrElementType, columns } =
    useModeTableProps({
      state: wrapperState,
      horizontalScroll,
      actionCellWidth,
      actionCellProps,
      dragAndDrop,
    });

  useEffect(() => {
    runInAction(() => {
      state.virtual.rowHeight = rowHeight;
    });
  }, [rowHeight, state]);

  useEffect(() => {
    if (estimatedRowHeight == null) {
      return;
    }
    runInAction(() => {
      state.virtual.estimatedRowHeight = estimatedRowHeight;
    });
  }, [estimatedRowHeight, state]);

  let table = (
    <Table
      rowVerticalPadding={rowVerticalPadding}
      search={search === true ? <QuerySearch state={query.search} /> : search}
      {...rest}
      skin="neutral"
      showHeaderWhenEmpty
      sticky
      tabs={tabs}
      filters={filters}
      horizontalScroll={horizontalScroll}
      emptyState={emptyState}
      noResultsState={noResultsState}
      isApplyColumnWidthStyle
      showTitleBar={showTitleBar}
      {...getVirtualTableProps({ horizontalScroll })}
      TrElementType={TrElementType}
      state={state}
      BodyElementType={BodyElementType}
      columns={columns}
      dragAndDropReorderModeToolbar={dragAndDropReorderModeToolbar}
      dragAndDrop={dragAndDrop}
      dragAndDropCancel={dragAndDropCancel}
      dragAndDropSubmit={dragAndDropSubmit}
      dragAndDropBulkSubmit={dragAndDropBulkSubmit}
      dragAndDropCategories={dragAndDropCategories}
    >
      <MultiCollectionSupportProvider
        key={`MultiCollectionSupportProvider_${key}`}
        value={state.multi}
      >
        <TablePlaceholderStates
          key={`PlaceholderStates_${key}`}
          state={state}
          emptyState={emptyState}
          noResultsState={noResultsState}
          errorState={errorState}
          rowVerticalPadding={rowVerticalPadding}
          showTitleBar={showTitleBar}
        />
        <NestedTableContent key={`NestedTableContent_${key}`} state={state} />
      </MultiCollectionSupportProvider>
    </Table>
  );

  if (dragAndDrop) {
    const { NestedTableDragAndDropContext } = dragAndDrop;
    table = (
      <NestedTableDragAndDropContext
        state={wrapperState.nested}
        onSubmit={dragAndDropSubmit}
        onBulkSubmit={dragAndDropBulkSubmit}
      >
        {table}
      </NestedTableDragAndDropContext>
    );
  }

  return table;
}

export const NestedTableWSRTable = observer(_NestedTableWSRTable);
