import type { ComputedRef, Ref } from 'vue'
import { computed, nextTick, ref, unref, watch } from 'vue'
import { getViewportOffset } from '/@/utils/domUtils'
import { isBoolean } from '/@/utils/is'
import { useWindowSizeFn } from '/@/hooks/event/useWindowSizeFn'
import { useModalContext } from '/@/components/Modal'
import { onMountedOrActivated } from '/@/hooks/core/onMountedOrActivated'
import { useDebounceFn } from '@vueuse/core'
import type { BasicColumn, BasicTableProps, TableRowSelection } from '../types/table'

export function useTableScroll(
    propsRef: ComputedRef<BasicTableProps>,
    tableElRef: Ref<ComponentRef>,
    columnsRef: ComputedRef<BasicColumn[]>,
    rowSelectionRef: ComputedRef<TableRowSelection | null>,
    getDataSourceRef: ComputedRef<Recordable[]>,
    wrapRef: Ref<HTMLElement | null>,
    formRef: Ref<ComponentRef>,
) {
    const tableHeightRef: Ref<Nullable<number | string>> = ref(167)
    const modalFn = useModalContext()

    // Greater than animation time 280
    const debounceRedoHeight = useDebounceFn(redoHeight, 100)

    const getCanResize = computed(() => {
        const { canResize, scroll } = unref(propsRef)
        return canResize && !(scroll || {}).y
    })

    watch(
        () => [unref(getCanResize), unref(getDataSourceRef)?.length],
        () => {
            debounceRedoHeight()
        },
        {
            flush: 'post',
        },
    )

    function redoHeight() {
        nextTick(() => {
            calcTableHeight()
        })
    }

    function setHeight(height: number) {
        tableHeightRef.value = height
        //  Solve the problem of modal adaptive height calculation when the form is placed in the modal
        modalFn?.redoModalHeight?.()
    }

    // No need to repeat queries
    let paginationEl: HTMLElement | null
    let footerEl: HTMLElement | null
    let bodyEl: HTMLElement | null

    async function calcTableHeight() {
        const { resizeHeightOffset, pagination, maxHeight, isCanResizeParent, useSearchForm } = unref(propsRef)
        const tableData = unref(getDataSourceRef)

        const table = unref(tableElRef)
        if (!table) return

        const tableEl: Element = table.$el
        if (!tableEl) return

        if (!bodyEl) {
            bodyEl = tableEl.querySelector('.ant-table-body')
            if (!bodyEl) return
        }

        const hasScrollBarY = bodyEl.scrollHeight > bodyEl.clientHeight
        const hasScrollBarX = bodyEl.scrollWidth > bodyEl.clientWidth

        if (hasScrollBarY) {
            tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.remove('hide-scrollbar-y')
        } else {
            !tableEl.classList.contains('hide-scrollbar-y') && tableEl.classList.add('hide-scrollbar-y')
        }

        if (hasScrollBarX) {
            tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.remove('hide-scrollbar-x')
        } else {
            !tableEl.classList.contains('hide-scrollbar-x') && tableEl.classList.add('hide-scrollbar-x')
        }

        bodyEl!.style.height = 'unset'

        if (!unref(getCanResize) || !unref(tableData) || tableData.length === 0) return

        await nextTick()
        // Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight

        const headEl = tableEl.querySelector('.ant-table-thead ')

        if (!headEl) return

        // Table height from bottom height-custom offset
        let paddingHeight = 32
        // Pager height
        let paginationHeight = 2
        if (!isBoolean(pagination)) {
            paginationEl = tableEl.querySelector('.ant-pagination') as HTMLElement
            if (paginationEl) {
                const offsetHeight = paginationEl.offsetHeight
                paginationHeight += offsetHeight || 0
            } else {
                // TODO First fix 24
                paginationHeight += 24
            }
        } else {
            paginationHeight = -8
        }

        let footerHeight = 0
        if (!isBoolean(pagination)) {
            if (!footerEl) {
                footerEl = tableEl.querySelector('.ant-table-footer') as HTMLElement
            } else {
                const offsetHeight = footerEl.offsetHeight
                footerHeight += offsetHeight || 0
            }
        }

        let headerHeight = 0
        if (headEl) {
            headerHeight = (headEl as HTMLElement).offsetHeight
        }

        let bottomIncludeBody = 0
        if (unref(wrapRef) && isCanResizeParent) {
            const tablePadding = 12
            const formMargin = 16
            let paginationMargin = 10
            const wrapHeight = unref(wrapRef)?.offsetHeight ?? 0

            let formHeight = unref(formRef)?.$el.offsetHeight ?? 0
            if (formHeight) {
                formHeight += formMargin
            }
            if (isBoolean(pagination) && !pagination) {
                paginationMargin = 0
            }
            if (isBoolean(useSearchForm) && !useSearchForm) {
                paddingHeight = 0
            }

            const headerCellHeight = (tableEl.querySelector('.ant-table-title') as HTMLElement)?.offsetHeight ?? 0

            console.log(wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin)
            bottomIncludeBody = wrapHeight - formHeight - headerCellHeight - tablePadding - paginationMargin
        } else {
            // Table height from bottom
            bottomIncludeBody = getViewportOffset(headEl).bottomIncludeBody
        }

        let height =
            bottomIncludeBody -
            (resizeHeightOffset || 0) -
            paddingHeight -
            paginationHeight -
            footerHeight -
            headerHeight
        height = (height > maxHeight! ? (maxHeight as number) : height) ?? height
        setHeight(height)

        bodyEl!.style.height = `${height}px`
    }
    useWindowSizeFn(calcTableHeight, 280)
    onMountedOrActivated(() => {
        calcTableHeight()
        nextTick(() => {
            debounceRedoHeight()
        })
    })

    const getScrollX = computed(() => {
        let width = 0
        if (unref(rowSelectionRef)) {
            width += 60
        }

        // TODO props ?? 0;
        const NORMAL_WIDTH = 150

        const columns = unref(columnsRef).filter((item) => !item.defaultHidden)
        columns.forEach((item) => {
            width += Number.parseFloat(item.width as string) || 0
        })
        const unsetWidthColumns = columns.filter((item) => !Reflect.has(item, 'width'))

        const len = unsetWidthColumns.length
        if (len !== 0) {
            width += len * NORMAL_WIDTH
        }

        const table = unref(tableElRef)
        const tableWidth = table?.$el?.offsetWidth ?? 0
        return tableWidth > width ? '100%' : width
    })

    const getScrollRef = computed(() => {
        const tableHeight = unref(tableHeightRef)
        const { canResize, scroll } = unref(propsRef)
        return {
            x: unref(getScrollX),
            y: canResize ? tableHeight : null,
            scrollToFirstRowOnChange: false,
            ...scroll,
        }
    })

    return { getScrollRef, redoHeight }
}
