import React, { useEffect, useMemo, useRef, useState } from 'react'
import { PaginationProps, Table, TableColumnType, TableProps } from 'antd'
import type { SortOrder, ColumnGroupType, ColumnType } from 'antd/lib/table/interface'
import { Resizable } from 'react-resizable'
import ResizeObserver from 'rc-resize-observer'
import produce from 'immer'
import { nanoid } from 'nanoid'
import { getScrollbarWidth } from '..'
import { defaultPageSizeOptions } from '../hooks/page'
import ToolTip from './Tooltip'
import { Menu, useContextMenu } from 'react-contexify'
import { generateUUID } from ".."
import PermissionRcItem from './PermissionRcItem'

import 'react-contexify/dist/ReactContexify.css'
import './Table.less'

interface Props<RowType> {
  width: number
  maxHeight?: string | number
  pageSize: number
  pageNum: number
  total: number
  pageSizeOptions: string[] | number[]
  onPaginate: PaginationProps["onChange"]
  rowSelection?: TableProps<RowType>
  bodyCell: any
  extraColWidth?: number
  menuData: string[] 
  menuPermissions: string[]
  onMenuItemClick: Function
  onRowClick: Function
  shouldRowContextMenu: Function
}

const scrollbarWidth = getScrollbarWidth()


function FC<RowType extends object = any>({ width, maxHeight, pageSize, pageNum, total, pageSizeOptions, onPaginate, columns, bodyCell, extraColWidth = 0, menuData, menuPermissions, onMenuItemClick, onRowClick, shouldRowContextMenu, ...rest }: TableProps<RowType> & Props<RowType>) {
  type Columns = typeof columns
  const MENU_ID = generateUUID()
  const [tableWidth, setTableWidth] = useState(0)

  const { show } = useContextMenu({
    id: MENU_ID,
  })

  const paddingCol = useRef<TableColumnType<any>>({
    key: 'padding',
    width: 0,
    render: () => undefined
  })

  const handleResize = (index: number) => (e: any, { size }: any) => {
    setCols((prevCols) => {
      const nextColumns = [...(prevCols ?? [])];
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width,
      };
      return nextColumns;
    });
  };

  const [cols, setCols] = useState<Columns>()
  useEffect(() => {
    if (!!columns && tableWidth > 0) {
      const contentWidth = getWidth(width ?? tableWidth,extraColWidth)
      setDefaultWidth(columns, contentWidth)
      paddingCol.current.width = 0

      const newCols = columns
        .map((col, index) => {
          const render = getRender(col);
          const colWidth = col.width ?? 100;
          return {
            ellipsis: true,
            ...col, /* colRef: createRef(), */ width: colWidth, render,
            onHeaderCell: (column: any) => ({
              width: column.width,
              // colRef: column.colRef,
              onResize: handleResize(index),
            }),
          };
        })

      setCols(newCols)
    }
  }, [columns, tableWidth, width, extraColWidth])

  // add padding column
  const cols1 = useMemo(() => !!cols ? [...cols, paddingCol.current] : undefined, [cols, pageSize, pageNum])

  const scroll = useMemo(() => (maxHeight === undefined || total === 0 /* fix 暂无数据显示滚动条? */ ? { x: '100%' } : { y: maxHeight, x: '100%' /* 'max-content' 所有列显示全宽*/ }), [maxHeight, total])
  const ref = useRef<HTMLDivElement>(null)

  const [rightClickNode, setRightClickNode] = React.useState<any>(undefined)

  const handleContextMenu = (event: any, node: any) => {
    show(event, {
      position: {
        x: event.clientX + 30,
        y: event.clientY - 10
      }
    })
  }

  return (
    <ResizeObserver
      onResize={(size) => {
        setTableWidth(size?.width)
      }}
    >
      <Table
        ref={ref}
        className="ssetable"
        size='middle'
        rowKey="id" // could be overrided in rest.
        showSorterTooltip={false}
        columns={cols1}
        pagination={{
          pageSizeOptions: pageSizeOptions ?? defaultPageSizeOptions, showSizeChanger: true,
          position: ['bottomCenter'], pageSize, current: pageNum, total, onChange: onPaginate,
          showTotal: total => `共 ${total} 条`,
        }}
        components={{
          body: {
            cell: bodyCell ?? null
          },
          header: {
            cell: ResizableTitle,
          },
        }}
        onRow={(record, index) => {
          return {
            onClick: event => {
              onRowClick?.(event, record)
            },
            onContextMenu: event => {
              setRightClickNode(record)
              if (shouldRowContextMenu?.(record)) {
                handleContextMenu(event, record)
              } 
            },
          }
        }}
        scroll={scroll}
        {...rest}
      />
      <Menu id={MENU_ID}>
       {
         menuData?.map(item => <PermissionRcItem 
          key={item} 
          id={item} 
          disabled={rightClickNode?.[`${item}`]?.disabled}
          tip={rightClickNode?.[`${item}`]?.tip}
          permissions={rightClickNode?.permissions||menuPermissions}
          permissionKey={item}
          onClick={() => onMenuItemClick?.(item, rightClickNode)}>
            {item}
          </PermissionRcItem>)
       }
      </Menu>
    </ResizeObserver>
  )
}


// 可变列宽
const ResizableTitle = (props: any) => {
  const { onResize, width, ...restProps } = props;

  if (!width) {
    return <th {...restProps} />;
  }

  return (
    <Resizable
      width={width}
      height={0}
      handle={
        <span
          className="react-resizable-handle"
          onClick={e => {
            e.stopPropagation();
          }}
        />
      }
      onResize={onResize}
      draggableOpts={{ enableUserSelectHack: false }}
    >
      <th {...restProps} />
    </Resizable>
  );
};

function setDefaultWidth(columns: any[], width: number) {
  let rowWidth = 0, count = 0
  for (const col of columns) {
    if (typeof col.width === 'number') {
      rowWidth += col.width
    } else {
      count++
    }
  }
  if (count > 0) {
    const defaultW = (rowWidth > width ? 0 : width - rowWidth) / count
    for (const col of columns) {
      if (typeof col.width !== 'number') {
        col.width = (defaultW < 100) ? 100 : defaultW
      }
    }
  }
}

function getWidth(tableWidth: number, extraColWidth: number): number {
  return tableWidth - scrollbarWidth - extraColWidth // scrollbar width, checkbox column
}

function getRender<T>(col: ColumnGroupType<T> | ColumnType<T>) {
  return (value: any, record: T, index: number) => {
    // 用户自定render
    if (col.render) {
      const rs = col.render(value, record, index)
      if (typeof rs === 'string') {
        return (<ToolTip msg={rs} defaultStyle />)
      }
      return rs
    } else {
      return (<ToolTip msg={value} defaultStyle />)
    }
  }
}

export default FC

export function getStringSorter<T>(k: keyof T) {
  return (a: T, b: T, sortOrder?: SortOrder) => {
    const aVal = a[k], bVal = b[k]
    if (typeof aVal === 'string' && typeof bVal === 'string')
      return aVal.localeCompare(bVal);
    return 0
  }
}

export function getNumberSorter<T>(k: keyof T) {
  return (a: T, b: T, sortOrder?: SortOrder) => {
    const aVal = a[k], bVal = b[k]
    if (typeof aVal === 'number' && typeof bVal === 'number')
      return aVal - bVal;
    return 0
  }
}

export function generateId<T = any>(data: T[], id = 'id') {
  return produce(data, (draft) => {
    draft?.forEach((row: any) => {
      row[id] = nanoid()
    })
  })
}

export function generateIdFromArrayRow<T extends unknown[]>(data?: T[], id = 'id'): unknown[] | undefined {
  return data?.map((row, i) => {
    const obj: { [key: string]: unknown } = { [id]: nanoid() }
    row.forEach((cell, j) => {
      obj[j] = cell
    })
    return obj
  })
}

export function filterRows<RowType = unknown>(rows: RowType[] | undefined, filter: (row: RowType) => boolean) {
  if (rows) {
    const matched = rows.filter(filter)
    return matched
  }
  return rows
}