import { UI } from 'app/shared/store/ui/ui.constants';
import { getScreenWidth } from 'app/shared/store/ui/uiSelectors';
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import * as DataTable from './dataTable';
import dataTableHelper from './dataTable.helper';
import { CellValueType, ColumnConfig, ColumnHeader } from './dataTable.types';

interface Props<T> {
  config: ColumnConfig<T>[];
  data: T[];
  summary?: T;
  columnHeaders?: ColumnHeader[];
  onRowClick?: (row: T) => void;
  isSortable?: boolean;
  hideHeader?: boolean;
}

const getCell = <T, >(
  item: ColumnConfig<T>, 
  value: CellValueType, 
  defaultColumnWidth: number, 
  key: number, 
  isSummary?: boolean ) => {
  switch (item.cellType) {
    case 'boolean':
      return <DataTable.Cells.BoolCell
        key={`key-${key}`}
        value={value as boolean}
        width={item.width}
        align={item.align}
        defaultColumnWidth={defaultColumnWidth}
        extraClass={isSummary ? 'c-model-driven-data-table__cell--summary' : ''}
      />;
    case 'date':
    case 'fullDate':
      return <DataTable.Cells.DateCell
        key={`key-${key}`}
        value={value as string}
        width={item.width}
        align={item.align}
        defaultColumnWidth={defaultColumnWidth}
        showFullDate={item.cellType === 'fullDate'}
        extraClass={isSummary ? 'c-model-driven-data-table__cell--summary' : ''}
      />;
    case 'number':
      return <DataTable.Cells.NumberCell
        key={`key-${key}`}
        value={value as number}
        width={item.width}
        align={item.align}
        defaultColumnWidth={defaultColumnWidth}
        extraClass={isSummary ? 'c-model-driven-data-table__cell--summary' : ''}
        invertValueMarking={item.invertValueMarking}
      />;
    case 'text':
      return <DataTable.Cells.TextCell
        key={`key-${key}`}
        value={value as string}
        width={item.width}
        align={item.align}
        defaultColumnWidth={defaultColumnWidth}
        extraClass={isSummary ? 'c-model-driven-data-table__cell--summary' : ''}
      />;
    default:
      return 'Invalid cell type';
  }
};

const ModelDrivenDataTable = <T extends {}, >(
  { config, data, summary, columnHeaders, onRowClick, hideHeader = false, isSortable = true }: Props<T>) => {
  const [ orderedData, setData ] = useState<T[]>([]);
  const [ sortedColumn, setSortedColumn ] = useState(config[0].columnName);
  const [ isOrderAscending, setIsOrderAscending ] = useState(false);

  const screenWidth = useSelector(getScreenWidth);
  const isRowClickingDisabled = screenWidth < UI.BREAK_POINTS.LG;

  const getColumnConfig = (columnName: string) => {
    const columnConfig = config.find(item => item.columnName === columnName);
    if (!columnConfig) {
      throw `Couldn't find configuration for column ${columnName}. Invalid config.`;
    }

    return columnConfig;
  };

  useEffect(() => {
    if (isSortable) {
      const columnConfig = getColumnConfig(sortedColumn);
      const sortedData = dataTableHelper.reorderData(data, columnConfig.getValue, columnConfig.cellType, isOrderAscending);
      setData([ ...sortedData ]);
    } else {
      setData([ ...data ]);
    }
  }, [ data?.length, sortedColumn, isOrderAscending ]);

  const defaultColumnWidth = dataTableHelper.getDefaultColumnWidth(config);

  return (
    <>
      { data?.length > 0 &&
      <DataTable.ScrollableContainer>
        { columnHeaders &&
          <DataTable.ColumnsHeader headers={columnHeaders} />
        }
        {
          !hideHeader && 
          <DataTable.HeaderRow>
            {config.map((item, index) => <DataTable.HeaderRowColumn
              key={index}
              width={item.width}
              text={item.columnName}
              description={item.description}
              align={item.align}
              defaultColumnWidth={defaultColumnWidth}
              isColumnSorted={sortedColumn === item.columnName && isSortable}
              isAscendingOrder={isOrderAscending}
              onClick={isSortable ? () => {
                setSortedColumn(item.columnName);
                const newOrder = !isOrderAscending;
                setIsOrderAscending(newOrder);
              } : undefined}
            />)}
          </DataTable.HeaderRow>
        }
        {orderedData.map((item, index) =>
          <DataTable.DataRow 
            key={index} 
            onClick={isRowClickingDisabled ? undefined : onRowClick} 
            item={item} clickable={Boolean(onRowClick) && !isRowClickingDisabled}>
            {config.map((cfg, index) => getCell(cfg, cfg.getValue(item), defaultColumnWidth, index, (item as T & { highlighted?: boolean }).highlighted))}
          </DataTable.DataRow>
        )}
        {summary && <DataTable.DataRow 
          onClick={isRowClickingDisabled ? undefined : onRowClick} 
          item={summary} 
          clickable={Boolean(onRowClick) && !isRowClickingDisabled}>
          {config.map((cfg, index) => cfg.noSummary
            ? getCell({ ...cfg, cellType: 'text' }, '', defaultColumnWidth, index)
            : getCell(cfg, cfg.getValue(summary), defaultColumnWidth, index, true)
          )}
        </DataTable.DataRow>}
      </DataTable.ScrollableContainer>
      }
    </>
  );
};

export { ModelDrivenDataTable };
