import {Spin, Pagination} from 'antd';
import {
  createTablePageContext,
  createTableSearchContext,
  createTableSettingContext,
  useTablePageContext,
  useTableSearchContext,
} from '@hooks';
import {PAGE_SIZE_LIST, TABLE_CELL_WIDTH} from '@utils';
import {
  Dispatch,
  ReactElement,
  ReactNode,
  SetStateAction,
  useEffect,
  useState,
} from 'react';
import {useTable, useTableShadow} from './hooks';
import {ColumnSort, Row, RowSelectionState} from '@tanstack/react-table';
import './index.css';
import {ModifyData} from '@models';
import TableHead from './Header';
import TableBody from './Body';
import {klona} from 'klona/json';

type GroupKey<T extends Record<string, unknown>> = keyof T extends string
  ? `${keyof T}Group`
  : never;

export type LDColumnsType<T extends Record<string, unknown>> = {
  dataIndex: keyof T | GroupKey<T>,
  title: string,
  width?: number,
  render?: (info: T, index: number, row: Row<Record<string, any>>) => ReactNode,
  align?: 'left' | 'right' | 'center',
  fixed?: 'left' | 'right',
  sort?: boolean,
  children?: LDColumnsType<T>[],
};

type Props<T extends Record<string, unknown>> = {
  columns: LDColumnsType<T>[];
  data: T[];
  pageContext: ReturnType<typeof createTablePageContext>;
  searchContext: ReturnType<typeof createTableSearchContext>;
  settingContext: ReturnType<typeof createTableSettingContext>;
  count: number;
  'data-testid'?: string;
  pageSizeList?: string[];
  isSecondLevel?: boolean;
  rowSelection?: RowSelectionState;
  setRowSelection?: Dispatch<SetStateAction<RowSelectionState>>;
  disabledHeadSort?: boolean;
  disabledSizeChange?: boolean;
  highlightValue?: unknown;
  hightlightKey?: keyof T;
  enableRowDnd?: boolean;
  rawKey?: keyof T;
  onSortingChange?: (state: ColumnSort | null) => void;
  subRowKey?: keyof T;
  renderSubComponent?: (row: Row<Record<string, any>>) => ReactNode;
};

function LDTable<T extends Record<string, any>>(props: Props<T>): ReactElement {
  const {
    columns,
    data,
    pageContext,
    searchContext,
    count,
    pageSizeList = PAGE_SIZE_LIST,
    isSecondLevel,
    rowSelection,
    setRowSelection,
    settingContext,
    disabledHeadSort,
    disabledSizeChange,
    highlightValue,
    hightlightKey,
    rawKey,
    enableRowDnd,
    onSortingChange,
    subRowKey,
    renderSubComponent,
  } = props;
  const [klonaData, setKlonaData] = useState(klona(data));
  const [{page, pageSize}, {setPageContext}] = useTablePageContext(pageContext);
  const [{isSearching}] = useTableSearchContext(searchContext);

  useEffect(function() {
    enableRowDnd && setKlonaData(klona(data));
  }, [data, enableRowDnd]);

  const [
    {
      getHeaderGroups, getRowModel, getCenterTotalSize,
      active, hasSort, hasGroup,
    },
    {onDragEnd, onDragStart},
  ] = useTable(
    columns,
    enableRowDnd ? klonaData : data,
    {
      settingContext,
      rowSelection,
      setRowSelection,
      rawKey,
      onSortingChange,
      subRowKey,
      hasRenderSubComponent: Boolean(renderSubComponent),
    },
  );

  const {
    scrollProgess,
    scrollTableRef,
    headerTableRef,
  } = useTableShadow(getCenterTotalSize());

  return (
    <Spin spinning={isSearching}>
      <div
        className="ld-table-wrapper"
        id={props['data-testid'] ?? 'ld_table_wrapper'}
        data-testid={props['data-testid']}
      >
        <TableHead
          ref={headerTableRef}
          isSecondLevel={isSecondLevel}
          disabledHeadSort={disabledHeadSort || hasGroup}
          disabledSizeChange={disabledSizeChange}
          active={active}
          getHeaderGroups={getHeaderGroups}
          onDragStart={onDragStart}
          onDragEnd={onDragEnd}
          columns={columns}
          scrollProgess={scrollProgess}
          getCenterTotalSize={getCenterTotalSize}
        />

        <TableBody
          ref={scrollTableRef}
          scrollProgess={scrollProgess}
          getCenterTotalSize={getCenterTotalSize}
          getRowModel={getRowModel}
          highlightValue={highlightValue}
          hightlightKey={hightlightKey}
          getHeaderGroups={getHeaderGroups}
          data={klonaData}
          rawKey={rawKey}
          enableDnd={enableRowDnd && (!hasSort || Boolean(onSortingChange))}
          setData={setKlonaData}
          isSecondLevel={isSecondLevel}
          renderSubComponent={renderSubComponent}
        />
      </div>
      <Pagination
        className="ld-table-pagination"
        pageSize={pageSize}
        showQuickJumper
        pageSizeOptions={pageSizeList}
        total={count}
        showSizeChanger
        onChange={(page, pageSize) => setPageContext({page, pageSize})}
        current={page}
        showTotal={total => `共${total}条数据`}
      />
    </Spin>
  );
}

export default LDTable;

export const modifyDataColumns: LDColumnsType<ModifyData>[] = [
  {
    title: '最后修改人',
    dataIndex: 'modifyUser',
  },
  {
    title: '最后修改时间',
    dataIndex: 'modifyTime',
    width: TABLE_CELL_WIDTH.date,
  },
];
