import { defineComponent, h, ref, onMounted, onUnmounted, PropType, watch } from 'vue'
import ResizeObserver from 'resize-observer-polyfill'
import { useDrag } from './drag'
import './index.less'

interface CatTableColumn {
    prop: string;
    label: string;
    width: number;
}

/**
 * 通用表格组件(开发中)
 */
export default defineComponent({
    props: {
        columns: {
            type: Array as PropType<CatTableColumn[]>,
            default: () => ([])
        },
        rows: {
            default: () => ([])
        }
    },
    setup(props) {
        const { dragStart, drag, dragEnd } = useDrag();
        const tableElement = ref<HTMLDivElement>();
        const headerElement = ref<HTMLTableElement>();
        const bodyElement = ref<HTMLTableElement>();
        const headerColumns = ref<CatTableColumn[]>([]);
        const scrollbarWidth = ref(0); // 滚动条宽度

        const tableStyle = () => ({
            width: headerColumns.value.reduce((pre, cur) => pre += cur.width, 0) + 'px'
        })

        const renderColGroup = () => h('colgroup', headerColumns.value.map((column) => h('col', { width: column.width })));

        const renderHeader = () => h('div', {
            class: 'cat-table__wrapper'
        }, [
            h('table', {
                ref: headerElement,
                class: 'cat-table__header',
                cellspacing: 0,
                cellpadding: 0,
                style: tableStyle(),
            }, [
                renderColGroup(),
                h('thead', h('tr', headerColumns.value.map((column) => h('th', h('div', { class: 'cell' }, column.label)))))
            ])
        ])

        const renderBody = () => h('div', {
            class: 'cat-table__wrapper'
        }, [
            h('table', {
                ref: bodyElement,
                class: 'cat-table__body',
                cellspacing: 0,
                cellpadding: 0,
                style: tableStyle(),
            }, [
                renderColGroup(),
                h('tbody', props.rows.map((row) => {
                    return h('tr', headerColumns.value.map((column) => h('td', h('div', { class: 'cell' }, row[column.prop]))))
                }))
            ]),
            ...scrollbarWidth.value > 0 ? [renderScrollbar()] : [],
        ])

        const renderScrollbar = () => h('div', {
            class: 'cat-scrollbar',
        }, h('div', {
            class: 'cat-scrollbar__thumb',
            draggable: true,
            ondragstart: dragStart,
            ondrag: drag,
            ondragend: dragEnd,
            style: {
                width: scrollbarWidth.value + 'px'
            },
        }))

        const columnResize = (() => {
            let timer = 0;
            let prevWidth = 0; // 记录上次宽度

            return () => {
                const table = tableElement.value;
                if (table) {
                    const miniWidth = 48; // 限制列宽最小宽度
                    headerColumns.value = [];

                    // 计算出列宽的组合数据
                    const colgroup = props.columns.reduce((pre, cur) => {
                        if (cur.width > miniWidth) {
                            pre.width -= cur.width;
                            pre.length -= 1;
                        }
                        return pre;
                    }, {
                        width: table.clientWidth,
                        length: props.columns.length,
                    })

                    // 列宽平均分配
                    props.columns.forEach((column) => {
                        const item = { ...column };
                        if (!item.width) {
                            const width = Math.floor(colgroup.width / colgroup.length);
                            item.width = width > miniWidth ? width : miniWidth;
                        }
                        headerColumns.value.push(item)
                    })

                    // 判断是否显示滚动条
                    if (colgroup.width !== prevWidth) {
                        clearTimeout(timer);
                        scrollbarWidth.value = 0;

                        timer = window.setTimeout(() => {
                            prevWidth = colgroup.width;
                            const body = bodyElement.value;

                            if (body) {
                                const ratio = table.clientWidth / body.clientWidth;
                                if (ratio < 1) {
                                    scrollbarWidth.value = table.clientWidth * ratio;
                                }
                            }
                        }, 200)
                    }
                }
            }
        })()

        watch(() => props.columns, () => columnResize());

        onMounted(() => {
            const el = tableElement.value;
            if (el) {
                // 监听元素变化
                const resizeObserver = new ResizeObserver(columnResize);
                resizeObserver.observe(el);

                onUnmounted(() => {
                    resizeObserver.unobserve(el);
                })
            }
        })

        return () => h('div', {
            ref: tableElement,
            class: 'cat-table'
        }, [
            ...props.columns.length ? [renderHeader()] : [],
            ...props.rows.length ? [renderBody()] : [],
        ])
    }
})