<template>
    <!-- 虚拟列表容器 -->
    <scroll-view class="im-virtual-list" :scroll-y="true" :scroll-with-animation="true" :show-scrollbar="false"
        :enhanced="true" :bounces="false" :lower-threshold="lowerThreshold" :upper-threshold="upperThreshold"
        :scroll-top="scrollTop" :scroll-into-view="scrollIntoViewId" @scroll="handleScroll"
        @scrolltolower="handleScrollToLower" @scrolltoupper="handleScrollToUpper">
        <!-- 顶部加载区域 -->
        <view v-if="showTopLoading" class="list-loading loading-top">
            <slot name="topLoading" v-if="topStatus === 'loading'">
                <im-loading :size="50" :mask="false">
                    <view>加载中...</view>
                </im-loading>
            </slot>
            <slot name="topNoMore" v-if="topStatus === 'no-more'">
                <view>没有更多了</view>
            </slot>
            <slot name="topError" v-if="topStatus === 'error'">
                <view>加载失败，点击重试</view>
            </slot>
        </view>

        <!-- 实际渲染的列表项 -->
        <view v-for="item in visibleItems" :key="getItemKey(item)" :id="getItemId(item)" @click="handleItemClick(item)"
            @longpress="handleItemLongPress(item)">
            <slot :item="item.data" :index="getItemIndex(item)"></slot>
        </view>

        <!-- 底部加载区域 -->
        <view v-if="showBottomLoading" class="list-placeholder" style="min-height: calc(100vh - 400rpx) ;"></view>
        <view v-if="showBottomLoading" class="list-loading loading-bottom">
            <slot name="bottomLoading" v-if="bottomStatus === 'loading'">
                <im-loading :size="50" :mask="false">
                    <view>加载中...</view>
                </im-loading>
            </slot>
            <slot name="bottomNoMore" v-if="bottomStatus === 'no-more'">
                <view>没有更多了</view>
            </slot>
            <slot name="bottomError" v-if="bottomStatus === 'error'">
                <view>加载失败，点击重试</view>
            </slot>
        </view>

        <!-- 回到顶部按钮 -->
        <view v-if="showBackToTop && scrollDistance > backToTopThreshold" class="back-to-top" @click="scrollToTop">
            <text class="back-to-top-icon">↑</text>
        </view>
    </scroll-view>
</template>

<script setup lang="ts">
import { ref, computed, watch, nextTick, onMounted, onUnmounted, getCurrentInstance } from 'vue'
import ImLoading from '../im-loading/im-loading.vue'
import type {VirtualListItem, VirtualListProps,VirtualListEmits,ScrollEvent } from '../../types/components/virtual-list'

// 定义类型
// export interface VirtualListItem<T = any> {
//     data: T
//     index: number
//     height: number
//     offset: number
// }

// export type LoadingStatus = 'loading' | 'no-more' | 'error' | 'idle'

// export interface ScrollEvent {
//     detail: {
//         scrollTop: number
//         scrollLeft: number
//         scrollHeight: number
//         scrollWidth: number
//         deltaX: number
//         deltaY: number
//     }
// }

// Props 定义
const props = withDefaults(defineProps<VirtualListProps>(), {
    data: () => [],
    estimatedItemSize: 60,
    buffer: 5,
    height: '100%',
    keyField: 'id',
    showTopLoading: false,
    showBottomLoading: false,
    topStatus: 'idle',
    bottomStatus: 'idle',
    lowerThreshold: 50,
    upperThreshold: 50,
    showBackToTop: true,
    backToTopThreshold: 500,
    initialScrollTop: 0,
    scrollIntoView: '',
    keepScrollPosition: false
})

const emit = defineEmits<VirtualListEmits>()

// 响应式数据
const scrollTop = ref(props.initialScrollTop)
const scrollDistance = ref(0)
const scrollIntoViewId = ref('')
const containerHeight = ref(0)
const isScrolling = ref(false)

// 计算虚拟列表数据
const virtualListData = computed<VirtualListItem[]>(() => {
    const items: VirtualListItem[] = []
    let totalHeight = 0

    props.data.forEach((item, index) => {
        const itemHeight = getItemHeight(item, index)
        items.push({
            data: item,
            index,
            height: itemHeight,
            offset: totalHeight
        })
        totalHeight += itemHeight
    })

    return items
})

// 总高度
// const totalHeight = computed(() => {
//     const lastItem = virtualListData.value[virtualListData.value.length - 1]
//     return lastItem ? lastItem.offset + lastItem.height : 0
// })

// 可见区域计算
const visibleRange = computed(() => {
    const start = Math.max(0, Math.floor(scrollTop.value / props.estimatedItemSize) - props.buffer)
    const visibleCount = Math.ceil(containerHeight.value / props.estimatedItemSize)
    const end = Math.min(
        virtualListData.value.length,
        start + visibleCount + props.buffer * 2
    )
    return { start, end }
})

// 可见的项目
const visibleItems = computed(() => {
    const { start, end } = visibleRange.value
    return virtualListData.value.slice(start, end)
})

// 开始偏移量
// const startOffset = computed(() => {
//     const item = virtualListData.value[visibleRange.value.start]
//     return item ? item.offset : 0
// })

// 处理滚动事件
const handleScroll = (event: ScrollEvent) => {
    const { scrollTop: top, scrollHeight, scrollLeft } = event.detail
    scrollTop.value = top
    scrollDistance.value = top
    isScrolling.value = true

    emit('scroll', event)

    // 防抖处理
    clearScrollTimer()
    scrollTimer.value = setTimeout(() => {
        isScrolling.value = false
    }, 150)
}

// 滚动到底部
const handleScrollToLower = () => {
    if (props.bottomStatus === 'loading' || props.bottomStatus === 'no-more') return
    emit('scroll-to-lower')
    emit('bottom-load')
}

// 滚动到顶部
const handleScrollToUpper = () => {
    if (props.topStatus === 'loading' || props.topStatus === 'no-more') return
    emit('scroll-to-upper')
    emit('top-load')
}

// 点击项目
const handleItemClick = (item: VirtualListItem) => {
    emit('item-click', item.data, item.index)
}

// 长按项目
const handleItemLongPress = (item: VirtualListItem) => {
    emit('item-long-press', item.data, item.index)
}

// 回到顶部
const scrollToTop = () => {
    scrollTop.value = 0
    nextTick(() => {
        scrollTop.value = -1 // 触发滚动
    })
}

// 滚动到指定项目
const scrollToItem = (index: number, options: {
    align?: 'top' | 'center' | 'bottom'
    animated?: boolean
} = {}) => {
    const { align = 'top', animated = true } = options
    const item = virtualListData.value[index]
    if (!item) return

    let targetTop = item.offset
    if (align === 'center') {
        targetTop = item.offset - containerHeight.value / 2 + item.height / 2
    } else if (align === 'bottom') {
        targetTop = item.offset - containerHeight.value + item.height
    }

    scrollTop.value = Math.max(0, targetTop)

    if (!animated) {
        nextTick(() => {
            scrollTop.value = -1
        })
    }
}

// 获取项目高度（可扩展为动态高度）
const getItemHeight = (item: any, index: number): number => {
    // 这里可以根据实际需求实现动态高度计算
    return props.estimatedItemSize
}

// 获取项目唯一键
const getItemKey = (item: VirtualListItem): string | number => {
    return item.data[props.keyField] || item.index
}

// 获取项目ID（用于scroll-into-view）
const getItemId = (item: VirtualListItem): string => {
    return `item-${getItemKey(item)}`
}

// 获取项目样式
// const getItemStyle = (item: VirtualListItem) => {
//     return {
//         height: `${item.height}px`,
//         boxSizing: 'border-box' as any
//     }
// }

// 获取项目索引
const getItemIndex = (item: VirtualListItem): number => {
    return item.index
}

// 定时器
const scrollTimer = ref<NodeJS.Timeout>()

// 清理定时器
const clearScrollTimer = () => {
    if (scrollTimer.value) {
        clearTimeout(scrollTimer.value)
    }
}

// 测量容器高度
const measureContainer = () => {
    nextTick(() => {
        const query = uni.createSelectorQuery().in(getCurrentInstance())
        query.select('.im-virtual-list').boundingClientRect((rect: any) => {
            if (rect && rect.height) {
                containerHeight.value = rect.height
            }
        }).exec()
    })
}

// 监听数据变化，保持滚动位置
watch(() => props.data, () => {
    if (props.keepScrollPosition) {
        // 记录当前可见的第一个项目
        const firstVisibleItem = visibleItems.value[0]
        if (firstVisibleItem) {
            nextTick(() => {
                // 尝试滚动到之前的位置
                const targetIndex = firstVisibleItem.index
                if (targetIndex < props.data.length) {
                    scrollToItem(targetIndex, { align: 'top', animated: false })
                }
            })
        }
    }
}, { deep: true })

// 监听 scrollIntoView 变化
watch(() => props.scrollIntoView, (newVal) => {
    if (newVal) {
        scrollIntoViewId.value = newVal
        emit('update:scroll-into-view', '')
    }
})

// 生命周期
onMounted(() => {
    measureContainer()

    // 监听窗口变化
    uni.onWindowResize?.(() => {
        measureContainer()
    })
})

onUnmounted(() => {
    clearScrollTimer()

    if (uni.offWindowResize) {
        uni.offWindowResize((result: any) => {
        })
    }
})

// 暴露方法给父组件
defineExpose({
    scrollToTop,
    scrollToItem,
    scrollToIndex: scrollToItem,
    getItemHeight,
    getVisibleRange: () => visibleRange.value,
    getContainerHeight: () => containerHeight.value,
    getScrollTop: () => scrollTop.value,
    measureContainer
})
</script>

<style lang="scss" scoped>
.im-virtual-list {
    // min-height: 200rpx;
    // height: 100vh;
}

.list-placeholder {
    pointer-events: none;
}

.list-loading {
    // height: 100%;
    color: $im-text-color-lighter;
    text-align: center;
    // display: flex;
    // align-items: center;
    // justify-content: center;
    // height: 80rpx;
    // font-size: 28rpx;
    // color: #909399;
    // border: solid 1px red;

    &.loading-top {
        // position: absolute;
        // top: 0;
        // left: 0;
        // right: 0;
        // z-index: 10;
    }

    &.loading-bottom {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 10;
    }
}

.back-to-top {
    position: fixed;
    right: 32rpx;
    bottom: 128rpx;
    width: 80rpx;
    height: 80rpx;
    border-radius: 50%;
    background-color: #409EFF;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4rpx 12rpx rgba(64, 158, 255, 0.3);
    z-index: 100;
    transition: all 0.3s;

    &:active {
        transform: scale(0.95);
        background-color: #337ecc;
    }

    &-icon {
        color: white;
        font-size: 36rpx;
        font-weight: bold;
    }
}
</style>