import React, { ComponentType, useEffect, useMemo, useState } from 'react';
import { observer } from 'mobx-react-lite';
import {
  GridChildComponentProps,
  ReactElementType,
  VariableSizeGrid,
} from 'react-window';
import { useScrollableContentContext } from '../../providers';
import {
  ReactWindowGridRef,
  VirtualGridRepeaterState,
} from './VirtualGridRepeaterState';
import { RenderItem } from './RenderItem';
import { VirtualGridRepeaterContextProvider } from './VirtualGridRepeaterContext';
import { GridState } from './GridState';

export interface VirtualGridRepeaterBaseProps {
  gridState: GridState;
  renderItem: RenderItem;
  children: ComponentType<GridChildComponentProps<undefined>>;
  innerElementType?: ReactElementType;
  outerElementType?: ReactElementType;
}

function _VirtualGridRepeaterBase(props: VirtualGridRepeaterBaseProps) {
  const {
    gridState,
    renderItem,
    innerElementType,
    outerElementType,
    children,
  } = props;

  const { scrollableContentRef } = useScrollableContentContext();

  const [state] = useState(() => new VirtualGridRepeaterState({ gridState }));

  const {
    calcGridProps,
    rowCount,
    height,
    width,
    itemKeyRecycler: itemKey,
  } = state;

  const [onFullRenderEnd] = useState(() =>
    state.gridState.toolbar.fedopsReporter.onFullRenderStart?.(),
  );

  useEffect(() => {
    if (height && width) {
      onFullRenderEnd?.();
    }
  }, [height && width]);

  const {
    columnCount,
    columnWidthIncludingGap,
    rowHeightIncludingGap,
    overscanCount,
    estimatedRowHeight,
  } = calcGridProps;

  useEffect(() => {
    const container = scrollableContentRef?.current;

    return state.init({
      container,
    });
  }, []);

  const style = useMemo(
    () =>
      ({
        overflow: 'visible',
        height: '100%',
      } as const),
    [],
  );

  const context = useMemo(
    () => ({ state, renderItem, itemKey }),
    [renderItem, itemKey],
  );

  useEffect(() => {
    state.gridRef?.resetAfterIndices({
      columnIndex: 0,
      rowIndex: 0,
      shouldForceUpdate: true,
    });
  }, [height, width, calcGridProps]);

  return (
    <VirtualGridRepeaterContextProvider value={context}>
      <VariableSizeGrid
        ref={(el) => {
          state.gridRef = el as ReactWindowGridRef;
          state.gridState.gridRef = el as ReactWindowGridRef;
        }}
        height={height}
        width={width}
        columnCount={columnCount}
        outerElementType={outerElementType}
        innerElementType={innerElementType}
        columnWidth={() => columnWidthIncludingGap(0)}
        rowHeight={(index: number) =>
          rowHeightIncludingGap({
            index,
            key: itemKey({ rowIndex: index, columnIndex: 0 }),
          }) ?? estimatedRowHeight
        }
        estimatedRowHeight={estimatedRowHeight}
        rowCount={height && width ? rowCount : 0}
        overscanRowCount={overscanCount}
        itemKey={itemKey}
        style={style}
      >
        {children}
      </VariableSizeGrid>
    </VirtualGridRepeaterContextProvider>
  );
}

export const VirtualGridRepeaterBase = observer(_VirtualGridRepeaterBase);
