import {Spin, Pagination, Empty} from 'antd';
import {ColumnsType, ColumnType} from 'antd/es/table';
import {
  createPageContext,
  createSearchContext,
  usePage,
  useTableSearchState,
} from '@hooks';
import {PAGE_SIZE_LIST} from '@utils';
import {ReactElement} from 'react';
import {useTable} from './hooks';
import {flexRender} from '@tanstack/react-table';
import css from './index.module.css';
import HeaderTh from './header-th';
import {
  DndContext,
  PointerSensor,
  useSensor,
  DragOverlay,
  closestCenter,
} from '@dnd-kit/core';
import {
  SortableContext,
  horizontalListSortingStrategy,
} from '@dnd-kit/sortable';
import classNames from 'classnames';

type Props<T> = {
  columns: ColumnsType<T>;
  data: T[];
  pageContext: ReturnType<typeof createPageContext>;
  searchContext: ReturnType<typeof createSearchContext>;
  count: number;
  /** @deprecated */
  rowKey?: string;
  'data-testid'?: string;
  pageSizeList?: string[];
  preloadKey?: string;
  isSecondLevel?: boolean;
};

function Table<T extends Record<string, any>>(props: Props<T>): ReactElement {
  const {
    columns,
    data,
    pageContext,
    searchContext,
    count,
    pageSizeList = PAGE_SIZE_LIST,
    preloadKey,
    isSecondLevel,
  } = props;
  const [{page, pageSize}, {onPageChange}] = usePage(pageContext);
  const [isSearching] = useTableSearchState(searchContext);

  const [
    {getHeaderGroups, getRowModel, getCenterTotalSize, active},
    {onDragEnd, onDragStart},
  ] = useTable(columns, data, {pageSize, preloadKey, searchContext});

  const sensor = useSensor(PointerSensor);

  return (
    <Spin spinning={isSearching}>
      <div
        className={css.tableWrapper}
        id='table_wrapper'
        data-testid={props['data-testid']}
      >
        <DndContext
          onDragStart={onDragStart}
          onDragEnd={onDragEnd}
          sensors={[sensor]}
          collisionDetection={closestCenter}
        >
          <SortableContext
            items={(columns as ColumnType<T>[]).map(val =>
              val.dataIndex!.toString(),
            )}
            strategy={horizontalListSortingStrategy}
          >
            <table className={css.table} style={{width: getCenterTotalSize()}}>
              <thead className={css.tableHead}>
                {getHeaderGroups().map(function ({id, headers}) {
                  return (
                    <tr key={id}>
                      {headers.map(header => (
                        <HeaderTh key={header.id} header={header} />
                      ))}
                    </tr>
                  );
                })}
              </thead>
              <tbody className={css.tableBody}>
                {getRowModel().rows.length > 0 ? (
                  getRowModel().rows.map(function ({id, getVisibleCells}) {
                    return (
                      <tr key={id}>
                        {getVisibleCells().map(function ({
                          id,
                          column,
                          getContext,
                        }) {
                          const {align, fixed} = column.columnDef.meta as {
                            align?: 'left' | 'center' | 'right';
                            fixed: boolean;
                          };
                          return (
                            <td
                              key={id}
                              className={classNames({[css.fixedRight]: fixed})}
                              style={{
                                width: column.getSize(),
                                textAlign: align ?? 'left',
                              }}
                            >
                              {flexRender(column.columnDef.cell, getContext())}
                            </td>
                          );
                        })}
                      </tr>
                    );
                  })
                ) : (
                  <tr>
                    <td
                      colSpan={getHeaderGroups()[0].headers.length}
                      style={{padding: 0}}
                    >
                      <Empty
                        image={Empty.PRESENTED_IMAGE_SIMPLE}
                        style={{
                          width: '400px',
                          position: 'sticky',
                          left: '50%',
                          transform: 'translateX(-50%)',
                          overflow: 'hidden',
                          margin: 0,
                          padding: '50px 10px',
                        }}
                      />
                    </td>
                  </tr>
                )}
              </tbody>
            </table>
            <DragOverlay>
              {active ? (
                <HeaderTh
                  header={active}
                  useDiv
                  isSecondLevel={isSecondLevel}
                />
              ) : null}
            </DragOverlay>
          </SortableContext>
        </DndContext>
      </div>
      <Pagination
        className={css.pagination}
        pageSize={pageSize}
        showQuickJumper
        pageSizeOptions={pageSizeList}
        total={count}
        showSizeChanger
        onChange={onPageChange}
        current={page}
        showTotal={total => `共${total}条数据`}
      />
    </Spin>
  );
}

export default Table;
