import React, { Suspense, useEffect, useMemo } from 'react';
import { FiltersMap } from '@wix/bex-core';
import { observer } from 'mobx-react-lite';
import { Table, TableProps } from '../Table';
import { Grid, GridProps } from '../Grid';
import type { EditableTableProps } from '../EditableTable';
import { InitialLoader } from '../InitialLoader';
import { LayoutSwitchButton } from '../LayoutSwitchButton';
import type { ILayoutSwitchState } from '../../state/ILayoutSwitchState';

const LazyEditableTable = React.lazy(() =>
  import('../EditableTable').then((m) => ({
    default: m.EditableTable as React.ComponentType<any>,
  })),
);

export interface LayoutSwitchProps<T, F extends FiltersMap> {
  state: ILayoutSwitchState<T, F>;
  tableProps?: Omit<TableProps<T, F>, 'tableGridSwitchButton'>;
  gridProps?: Omit<GridProps<T, F>, 'tableGridSwitchButton'>;
  spreadsheetProps?: Omit<EditableTableProps<T, F>, 'tableGridSwitchButton'>;
}

function _LayoutSwitch<T, F extends FiltersMap>({
  state,
  tableProps,
  gridProps,
  spreadsheetProps,
}: LayoutSwitchProps<T, F>) {
  const { viewTypeState, initTask, toolbar } = state;
  const isLoading = initTask.status.isIdle || initTask.status.isLoading;

  // Recompute only when a prop flips between defined and undefined.
  const availableOptions = useMemo(
    () =>
      viewTypeState.options.filter((option) => {
        if (option === 'table') {
          return !!tableProps;
        }
        if (option === 'grid') {
          return !!gridProps;
        }
        if (option === 'spreadsheet') {
          return !!spreadsheetProps;
        }
        return false;
      }),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [!!tableProps, !!gridProps, !!spreadsheetProps],
  );

  useEffect(() => state.init(), []);

  // If the stored viewType is not among the available options (e.g. 'grid' was
  // persisted but gridProps is not provided), persist the correction so the next
  // load starts from a valid value. changeViewType also updates dataCapsule.
  useEffect(() => {
    if (
      availableOptions.length > 0 &&
      !availableOptions.includes(viewTypeState.viewType)
    ) {
      viewTypeState.changeViewType(availableOptions[0]!);
    }
  }, [availableOptions, viewTypeState.viewType]);

  if (!availableOptions.length) {
    console.error(
      '[LayoutSwitch] At least one of tableProps, gridProps, or spreadsheetProps must be provided.',
    );
    return null;
  }

  const layoutSwitchButton = (
    <LayoutSwitchButton state={viewTypeState} options={availableOptions} />
  );

  if (isLoading) {
    return <InitialLoader dataHook="initial-loader" state={toolbar} />;
  }

  // If viewType is not yet available (loaded from storage but xProp absent),
  // fall back locally without waiting for the correction effect to fire.
  const activeView = availableOptions.includes(viewTypeState.viewType)
    ? viewTypeState.viewType
    : availableOptions[0];

  if (activeView === 'table') {
    return (
      <div data-hook="layout-view-table" style={{ display: 'contents' }}>
        <Table {...tableProps!} tableGridSwitchButton={layoutSwitchButton} />
      </div>
    );
  }

  if (activeView === 'grid') {
    return (
      <div data-hook="layout-view-grid" style={{ display: 'contents' }}>
        <Grid {...gridProps!} tableGridSwitchButton={layoutSwitchButton} />
      </div>
    );
  }

  if (activeView === 'spreadsheet') {
    return (
      <div data-hook="layout-view-spreadsheet" style={{ display: 'contents' }}>
        <Suspense
          fallback={<InitialLoader dataHook="initial-loader" state={toolbar} />}
        >
          <LazyEditableTable
            {...spreadsheetProps!}
            tableGridSwitchButton={layoutSwitchButton}
          />
        </Suspense>
      </div>
    );
  }

  return null;
}

export const LayoutSwitch = observer(_LayoutSwitch);
