import React, { Component } from 'react';
import { Checkbox } from 'antd';
import memoizeOne from 'memoize-one';
import { ScrollSync, Grid, AutoSizer } from 'react-virtualized';
import 'react-virtualized/styles.css';
import _ from 'lodash';
import styles from './Table.less';
import { TableProps, TableState } from './interface';
import Column from './Column';
import Cell from './Cell';
import extendIcon from '../assets/extend.png';
import IconFont from './base/extra/iconFont';
import scrollbarSize from 'dom-helpers/scrollbarSize';
import { getMergeClassName, getMergeStyle } from '@/apollo-table/utils/utils';

const borderStyle = '1px solid #e8e8e8';

export default class AirTable extends Component<TableProps, TableState> {
    private indexCount: any;
    config: any;
    memoizeLeftCount: Function;
    memoizeData: Function;
    static getDerivedStateFromProps(nextProps: TableProps, prevState: TableState) {
        const { columns, dataSource } = prevState;
        let nextState: TableState = {
            ...prevState,
        };
        if (JSON.stringify(dataSource) !== JSON.stringify(nextProps.dataSource)) {
            nextState.dataSource = nextProps.dataSource;
        }
        if (JSON.stringify(columns) !== JSON.stringify(nextProps.columns)) {
            nextState.columns = nextProps.columns;
        }
        return nextState;
    }
    constructor(props: TableProps) {
        super(props);
        const { columns, dataSource, width, height } = props;
        this.state = {
            columns,
            dataSource,
            tableWidth: width || document.body.clientWidth,
            tableHeight: height || document.body.clientHeight - 40,
        };
        this.config = {
            overscanColumnCount: 5,
            overscanRowCount: 5,
            columnWidth: 200,
            rowHeight: 40,
        };
        this.memoizeLeftCount = memoizeOne(this.getLeftCount);
        this.memoizeData = memoizeOne(this.filterData);
        this.indexCount = {};
    }
    componentDidMount() {
        window.addEventListener('resize', this.resize, false);
    }
    componentWillUnmount() {
        window.removeEventListener('resize', this.resize, false);
    }
    //重置窗口高度
    resize = () => {
        this.setState({
            tableHeight: document.body.clientHeight - 40,
            tableWidth: document.body.clientWidth,
        });
    };
    //获取左侧固定列数量
    getLeftCount = (columns: []) => {
        let len = 0;
        columns.map((item: any) => {
            if (item.fixed) {
                len += 1;
            }
        });
        return len;
    };
    //表头隐藏时过滤数据源
    filterData = (columns: [], dataSource: []) => {
        if (columns.length === 0 || dataSource.length === 0) {
            return [];
        }
        let cloneData = _.cloneDeep(dataSource);
        let i = 0;
        this.indexCount = {};
        cloneData.map((item1: any) => {
            const itemData = item1;
            itemData.rowData = itemData.rowData.filter((item2: any) =>
                columns.some((temp: any) => temp.columnName === item2.colName),
            );
            if (itemData.groupId) {
                if (this.indexCount[itemData.groupId]) {
                    this.indexCount[itemData.groupId].push(itemData.id);
                } else {
                    i += 1;
                    this.indexCount[itemData.groupId] = [itemData.id];
                }
                itemData.index = i;
            }
            return itemData;
        });
        return cloneData;
    };
    // 下拉加载
    onScroll = ({ clientHeight, scrollHeight, scrollTop }: any) => {
        const height = clientHeight + scrollTop || 0;
        const { onScroll, distanceToLoad = 100 } = this.props;
        if (scrollTop > 0 && height + distanceToLoad >= scrollHeight && typeof onScroll === 'function') {
            onScroll();
        }
    };
    //渲染表头
    renderHeaderCell = ({ columnIndex, key, rowIndex, style }: any) => {
        const { columns } = this.state;
        if (columns.length === 0) return null;
        const { columnType, columnChsName, width, columnAttrObj } = columns[columnIndex] || {};
        return (
            <div className={styles.leftHeaderCell} key={key} style={{ ...style, width: width || 200 }}>
                <Column type={String(columnType)} title={columnChsName} width={width} columnAttrObj={columnAttrObj} />
            </div>
        );
    };
    renderBodyRow = (data: any[], { columnIndex, key, rowIndex, style }: any) => {
        const { rowClassName, rowStyle, bordered = false } = this.props;
        // 默认边框覆盖掉传过来的样式
        const rowBorderStyle: any = {
            borderLeft: 'none',
            borderRight: 'none',
            borderTop: 'none',
            borderBottom: borderStyle,
        };
        if (bordered) {
            rowBorderStyle.borderRight = borderStyle;
            if (columnIndex === 0) {
                rowBorderStyle.borderLeft = borderStyle;
            }
        }
        const className = getMergeClassName(styles.bodyCell, rowClassName, { rowIndex });
        const rowStyleObject = getMergeStyle(style, rowStyle, { rowIndex });
        const mergedRowStyle = {
            ...rowStyleObject,
            ...rowBorderStyle,
        };
        return this.renderBodyCellContainer(data, {
            columnIndex,
            key,
            rowIndex,
            rowClassName: className,
            rowStyle: mergedRowStyle,
        });
    };

    renderBodyCellContainer = (data: any[], { columnIndex, key, rowIndex, rowClassName, rowStyle }: any) => {
        const { columns } = this.state;
        const columnConfig = columns[columnIndex];
        const { cellClassName, cellStyle } = columnConfig;
        const className = getMergeClassName(rowClassName, cellClassName, { columnIndex });
        const mergedCellStyle = getMergeStyle(rowStyle, cellStyle, { columnIndex });
        return this.renderBodyCell(data, {
            columnIndex,
            key,
            rowIndex,
            cellClassName: className,
            cellStyle: mergedCellStyle,
        });
    };

    //渲染数据
    renderBodyCell = (data: any[], { columnIndex, key, rowIndex, cellClassName, cellStyle }: any) => {
        const { columns, dataSource } = this.state;
        const { emitChangeCell } = this.props;
        if (columns.length === 0 || data.length === 0) {
            return;
        }
        const rowData: any = dataSource[rowIndex]; // 原始行数据，真实使用的数据
        const columnConfig: any = columns[columnIndex]; // 列属性
        const columnData: any = rowData.rowData[columnIndex]; // 列数据
        const cellData: any = columnData.cellValueList; // 列数据

        return (
            <Cell
                key={key}
                rowIndex={rowIndex}
                columnIndex={columnIndex}
                columnConfig={columnConfig}
                rowData={rowData}
                cellData={cellData}
                emitChangeCell={emitChangeCell}
                cellClassName={cellClassName}
                cellStyle={cellStyle}
            />
        );
    };

    render() {
        const { columns, dataSource, tableHeight = 0, tableWidth = 0 } = this.state;
        const { overscanColumnCount, overscanRowCount, columnWidth, rowHeight } = this.config;
        let totalHeight = tableHeight;
        let colWidth = columnWidth;
        const columnCount = columns.length;
        const rowCount = dataSource.length;
        if (rowCount > 0 && rowCount * rowHeight < tableHeight) {
            // 表格行数少于一屏高度时，高度增加横向滚动条高度
            totalHeight = rowCount * rowHeight + scrollbarSize();
        }
        if (columnCount > 0 && columnCount * columnWidth < tableWidth) {
            // 表格宽度不足一屏时，按屏幕宽度平分每列宽度
            colWidth = Math.floor(tableWidth / columnCount);
        }
        //有隐藏列时，修正数据与列头不匹配问题
        const data = this.memoizeData(columns, dataSource);
        //左侧固定列数量
        const leftCount = this.memoizeLeftCount(columns);

        return (
            <ScrollSync>
                {({ onScroll, scrollLeft, scrollTop }: any) => {
                    return (
                        <div className={styles.GridRow}>
                            <div
                                className={styles.LeftSideContainer}
                                style={{
                                    width: `${colWidth * leftCount}px`,
                                    height: `${totalHeight - scrollbarSize() + rowHeight}px`,
                                }}
                            >
                                {
                                    //左侧表头
                                    <div
                                        className={styles.LeftSideGridContainer}
                                        style={{
                                            position: 'absolute',
                                            left: 0,
                                            top: 0,
                                            backgroundColor: `rgba(246, 246, 246, 1)`,
                                            borderLeft: '1px solid #e8e8e8',
                                        }}
                                    >
                                        <Grid
                                            className={styles.HeaderGrid}
                                            columnData={columns}
                                            columnWidth={colWidth}
                                            columnCount={leftCount}
                                            width={colWidth * leftCount}
                                            rowHeight={rowHeight}
                                            rowCount={1}
                                            height={rowHeight}
                                            dataSource={dataSource}
                                            cellRenderer={this.renderHeaderCell}
                                        />
                                    </div>
                                }
                                {
                                    //左侧固定列
                                    <div
                                        className={styles.LeftSideGridContainer}
                                        style={{
                                            position: 'absolute',
                                            left: 0,
                                            top: rowHeight,
                                            borderLeft: '1px solid #e8e8e8',
                                        }}
                                    >
                                        <Grid
                                            className={styles.LeftSideGrid}
                                            overscanRowCount={overscanRowCount}
                                            cellRenderer={this.renderBodyRow.bind(this, data)}
                                            columnWidth={colWidth}
                                            columnCount={leftCount}
                                            width={colWidth * leftCount}
                                            rowHeight={rowHeight}
                                            rowCount={rowCount}
                                            height={totalHeight - scrollbarSize()}
                                            scrollTop={scrollTop}
                                            dataSource={dataSource}
                                            columns={columns}
                                        />
                                    </div>
                                }
                            </div>
                            <div className={styles.GridColumn}>
                                <AutoSizer disableHeight>
                                    {({ width }: any) => {
                                        // 如果列太少不满一屏时，列头宽度按列计算
                                        let headerWidth = width;
                                        if (rowCount * rowHeight > tableHeight) {
                                            // 表格行数大于一屏的高度时出现竖向滚动条，此时宽度减出滚动条宽度
                                            headerWidth -= scrollbarSize();
                                        }
                                        return (
                                            <div>
                                                {
                                                    //右侧表头
                                                    <div
                                                        style={{
                                                            backgroundColor: `rgba(246, 246, 246, 1)`,
                                                            height: rowHeight,
                                                            width: headerWidth,
                                                        }}
                                                    >
                                                        <Grid
                                                            className={styles.HeaderGrid}
                                                            overscanColumnCount={overscanColumnCount}
                                                            columnData={columns}
                                                            columnWidth={colWidth}
                                                            columnCount={columnCount}
                                                            width={headerWidth}
                                                            rowHeight={rowHeight}
                                                            rowCount={1}
                                                            height={rowHeight}
                                                            scrollLeft={scrollLeft}
                                                            cellRenderer={this.renderHeaderCell}
                                                        />
                                                    </div>
                                                }
                                                {
                                                    //右侧内容
                                                    <div
                                                        style={{
                                                            height: totalHeight,
                                                            width,
                                                        }}
                                                    >
                                                        <Grid
                                                            className={styles.BodyGrid}
                                                            overscanColumnCount={overscanColumnCount}
                                                            overscanRowCount={overscanRowCount}
                                                            dataSource={dataSource}
                                                            columnWidth={colWidth}
                                                            columnCount={columnCount}
                                                            width={width}
                                                            rowHeight={rowHeight}
                                                            rowCount={rowCount}
                                                            height={totalHeight}
                                                            onScroll={(...arg: Array<Object>) => {
                                                                onScroll(...arg);
                                                                this.onScroll(arg[0]);
                                                            }}
                                                            cellRenderer={this.renderBodyRow.bind(this, data)}
                                                            columns={columns}
                                                        />
                                                    </div>
                                                }
                                            </div>
                                        );
                                    }}
                                </AutoSizer>
                            </div>
                        </div>
                    );
                }}
            </ScrollSync>
        );
    }
}
