import React, { useEffect, useState, useRef, useMemo } from 'react';
import { Table } from 'antd';
import { Resizable } from 'react-resizable';
import ResizeObserver from 'rc-resize-observer'

const scrollbarWidth = getScrollbarWidth()

const ResizeableHeaderCell = props => {
  const { onResize, width, onClick, ...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
        onClick={onClick}
        {...restProps}
      />
    </Resizable>
  );
};

const ResizeableTable = (props) => {
  const { columns, extraColWidth = 0, ...restProps } = props

  const [tableWidth, setTableWidth] = useState(0)

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

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

  const [cols, setCols] = useState();

  useEffect(() => {
    if (!!columns && tableWidth > 0) {
      const contentWidth = getWidth(tableWidth, extraColWidth)
      setDefaultWidth(columns, contentWidth)
      paddingCol.current.width = 0

      const cols = columns
        .map((col, index) => {
          const colWidth = col.width ?? 100;
          return {
            ...col,  
            width: colWidth, 
            ellipsis: true,
            onHeaderCell: (column: any) => ({
              width: column.width,
              onResize: handleResize(index),
            }),
          };
        })
      setCols(cols)
    }
  }, [columns, tableWidth, extraColWidth])

  const cols1 = useMemo(() => !!cols ? [...cols, paddingCol.current] : undefined, [cols])

  return (
    <ResizeObserver
      onResize={({ width }) => {
        setTableWidth(width)
      }}
    >
      <Table 
        components={{
          header: {
            cell: ResizeableHeaderCell,
          }
        }}
        columns={cols1}
        { ...restProps }
      />
    </ResizeObserver>
  );
}

export default ResizeableTable;

function getWidth(tableWidth, extraColWidth) {
  // FIXME 判断没有选择列时,32为0
  return tableWidth - scrollbarWidth - extraColWidth // scrollbar width, checkbox column
}

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

export function getScrollbarWidth() {
  // Creating invisible container
  const outer = document.createElement('div');
  outer.style.visibility = 'hidden';
  outer.style.overflow = 'scroll'; // forcing scrollbar to appear
  outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
  document.body.appendChild(outer);

  // Creating inner element and placing it in the container
  const inner = document.createElement('div');
  outer.appendChild(inner);

  // Calculating difference between container's full width and the child width
  const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);

  // Removing temporary elements from the DOM
  outer.parentNode?.removeChild(outer);

  return scrollbarWidth;
}