import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { ColDef, GridApi, GridReadyEvent, GridOptions } from 'ag-grid-community';
import { bem } from 'utils/bem';
import { Loading } from 'common-v2/types';
import { CommonTable, ErrorView, TableLoader } from 'common-v2/components';
import { DEFAULT_ROW_HEIGHT, HEADER_HEIGHT } from 'label-permissions/constants';
import ErrorImage from 'assets/error_failed_to_load.png';
import { EmptyTableView } from '../empty-table-view';
import { EmptyViewMode, EmptyViewParams } from './types';
import { getEmptyViewMode } from './transducers';
import { BEM_CLASS, SReusableTable } from './s-reusable-table';

interface ReusableTableProps<T> extends GridOptions<T> {
  data: T[];
  fetchData(): void;
  getTableConfig(emptyViewMode: EmptyViewMode): ColDef[];
  loading: Loading;
  isSearchActive: boolean;
  errorMessage: React.ReactNode;
  emptyMessage: React.ReactNode;
  onTableResize?(api: GridApi<T[]>): void;
}

const classes = bem(BEM_CLASS);

export const Root = <T,>({
  data,
  fetchData,
  getTableConfig,
  loading,
  isSearchActive,
  errorMessage,
  emptyMessage,
  onTableResize,
  ...agGridProps
}: ReusableTableProps<T>) => {
  const gridApi = useRef<GridApi<T[]> | null>(null);
  const isGridReady = gridApi.current !== undefined;
  const isDataExist = data.length > 0;

  const emptyViewMode = useMemo(() => getEmptyViewMode({ loading, isDataExist, isSearchActive }), [
    isDataExist,
    isSearchActive,
    loading,
  ]);

  const tableConfig = useMemo(() => getTableConfig(emptyViewMode), [emptyViewMode, getTableConfig]);

  const emptyViewParams = useMemo<EmptyViewParams>(
    () => ({
      mode: emptyViewMode,
      fetchData,
    }),
    [emptyViewMode, fetchData]
  );

  const renderEmptyView = useCallback(
    ({ mode, fetchData }: EmptyViewParams) => {
      switch (mode) {
        case EmptyViewMode.Default:
          return <EmptyTableView>{emptyMessage}</EmptyTableView>;
        case EmptyViewMode.Search:
          return (
            <EmptyTableView>
              No results found.
              <br />
              Please try editing your query.
            </EmptyTableView>
          );
        case EmptyViewMode.Loading:
          return <TableLoader />;
        case EmptyViewMode.Error:
          return (
            <ErrorView
              className={classes('error')}
              action={fetchData}
              config={{
                description: errorMessage,
                actionTitle: 'Refresh',
                bottomImageSrc: ErrorImage,
              }}
            />
          );
        case EmptyViewMode.None:
          return '';
      }
    },
    [emptyMessage, errorMessage]
  );

  const onGridReady = useCallback(({ api }: GridReadyEvent) => {
    gridApi.current = api;
  }, []);

  const onGridSizeChanged = useCallback(() => {
    if (!gridApi?.current || !onTableResize) return;

    onTableResize(gridApi.current);
  }, [gridApi, onTableResize]);

  useEffect(() => {
    if (emptyViewMode === EmptyViewMode.None) {
      gridApi.current?.hideOverlay();
    } else {
      gridApi.current?.showNoRowsOverlay();
    }
  }, [emptyViewMode]);

  useEffect(() => {
    gridApi.current?.setColumnDefs(tableConfig);
  }, [tableConfig]);

  useEffect(() => {
    if (isGridReady) {
      fetchData();
    }
  }, [fetchData, isGridReady]);

  return (
    <SReusableTable>
      <CommonTable
        {...agGridProps}
        onGridReady={onGridReady}
        onGridSizeChanged={onGridSizeChanged}
        headerHeight={HEADER_HEIGHT}
        rowHeight={DEFAULT_ROW_HEIGHT}
        columnDefs={tableConfig}
        rowData={data}
        noRowsOverlayComponent={renderEmptyView}
        noRowsOverlayComponentParams={emptyViewParams}
        suppressContextMenu
        suppressCellFocus
        suppressRowHoverHighlight
        suppressDragLeaveHidesColumns
        suppressMovableColumns
        suppressMultiSort
      />
    </SReusableTable>
  );
};

export const ReusableTable = React.memo(Root) as typeof Root;
