<template>
  <!--
    分页增量滚动容器
    - 滚到底部自动 page++，直到全部渲染完
    - 通过 slot 暴露每一项，让调用方自己决定渲染
  -->
  <el-scrollbar ref="scrollbarRef" class="w-full h-full">
    <slot v-for="(item, idx) in displayItems" :item="item" :index="idx" :key="idx"></slot>
    <div
      v-if="showFooter"
      class="py-3 text-xs text-center text-[var(--el-text-color-secondary)]"
    >
      已到底部
    </div>
  </el-scrollbar>
</template>

<script lang="ts" setup generic="T">
import { computed, onMounted, onBeforeUnmount, ref, useTemplateRef, watch } from 'vue'
import { ElScrollbar } from 'element-plus'

defineOptions({ name: 'ImPagedScroller' })

const props = withDefaults(
  defineProps<{
    items: T[] // 全量数据
    pageSize?: number // 每页渲染条数
    threshold?: number // 距底多少 px 触发下一页
  }>(),
  {
    pageSize: 30,
    threshold: 30
  }
)

const scrollbarRef = useTemplateRef<InstanceType<typeof ElScrollbar>>('scrollbarRef')
const page = ref(1)

const displayItems = computed(() => {
  const limit = Math.min(page.value * props.pageSize, props.items.length)
  return props.items.slice(0, limit)
})

const allLoaded = computed(() => displayItems.value.length >= props.items.length)

/** 仅当超过一页时才显示「已到底部」，避免短列表也出现这条提示 */
const showFooter = computed(() => allLoaded.value && props.items.length > props.pageSize)

// el-scrollbar 根节点是 overflow:hidden 的，真正的滚动容器是内部 .el-scrollbar__wrap
let wrapEl: HTMLElement | null = null

onMounted(() => {
  wrapEl = scrollbarRef.value?.$el?.querySelector('.el-scrollbar__wrap') ?? null
  wrapEl?.addEventListener('scroll', onScroll)
})

onBeforeUnmount(() => {
  wrapEl?.removeEventListener('scroll', onScroll)
})

/** 切换数据源（如切会话）时重置分页：避免新列表沿用旧 page，首屏出现空段 */
watch(
  () => props.items,
  () => {
    page.value = 1
  }
)

/** 滚到距底 threshold 内时自增 page，扩出下一段切片 */
function onScroll(e: Event) {
  const el = e.target as HTMLElement
  if (el.scrollTop + el.clientHeight < el.scrollHeight - props.threshold) {
    return
  }
  if (allLoaded.value) {
    return
  }
  page.value++
}

defineExpose({
  /** 手动滚到顶部 */
  scrollTop: () => {
    if (wrapEl) {
      wrapEl.scrollTop = 0
    }
  },
  /** 手动滚到底部 */
  scrollBottom: () => {
    if (wrapEl) {
      wrapEl.scrollTop = wrapEl.scrollHeight
    }
  }
})
</script>
