<template>
  <div ref="scrollContainer" class="custom-scroll-container" :style="containerStyle" @scroll="updateScrollbar">
    <slot></slot>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted, nextTick, computed, watch, defineExpose, defineEmits } from 'vue'
import { useRoute } from 'vue-router'

const emit = defineEmits(['scroll'])
const route = useRoute()

const props = defineProps({
  height: {
    type: String,
    default: '100%'
  },
  width: {
    type: String,
    default: '100%'
  },
  scrollbarWidth: {
    type: Number,
    default: 6
  },
  trackColor: {
    type: String,
    default: '#f1f1f1'
  },
  thumbColor: {
    type: String,
    default: '#c1c1c1'
  },
  thumbHoverColor: {
    type: String,
    default: '#a1a1a1'
  },
  topOffset: {
    type: Number,
    default: 0
  }
})

const scrollContainer = ref(null)
const thumbHeight = ref(0)
const thumbTop = ref(0)

const containerStyle = computed(() => ({
  height: props.height,
  width: props.width,
  '--scrollbar-width': `${props.scrollbarWidth}px`,
  '--track-color': props.trackColor,
  '--thumb-color': props.thumbColor,
  '--thumb-hover-color': props.thumbHoverColor,
  '--thumb-height': `${thumbHeight.value}px`,
  '--thumb-top': `${thumbTop.value + props.topOffset}px`,
  '--top-offset': `${props.topOffset}px`,
  '--scrollbar-visible': thumbHeight.value > 0 ? '1' : '0'
}))

const updateScrollbar = () => {
  if (!scrollContainer.value) return

  const container = scrollContainer.value
  const scrollTop = container.scrollTop
  const scrollHeight = container.scrollHeight
  const clientHeight = container.clientHeight

  // 检查是否需要显示滚动条
  const needsScrollbar = scrollHeight > clientHeight

  if (needsScrollbar) {
    // 计算滚动条滑块的高度和位置
    const scrollbarHeight = clientHeight
    const newThumbHeight = Math.max((clientHeight / scrollHeight) * scrollbarHeight, 20)
    const newThumbTop = (scrollTop / (scrollHeight - clientHeight)) * (scrollbarHeight - newThumbHeight)

    thumbHeight.value = newThumbHeight
    thumbTop.value = isNaN(newThumbTop) ? 0 : newThumbTop
  } else {
    // 隐藏滚动条
    thumbHeight.value = 0
    thumbTop.value = 0
  }

  // 触发滚动事件
  emit('scroll', {
    scrollTop,
    scrollHeight,
    clientHeight,
    scrollPercentage: getScrollPercentage(),
    needsScrollbar
  })
}

// 设置滚动位置为偏移量
const setScrollPosition = (position, duration = 0) => {
  if (!scrollContainer.value) return

  const container = scrollContainer.value
  const targetPosition = Math.max(0, Math.min(position, container.scrollHeight - container.clientHeight))

  if (duration <= 0) {
    container.scrollTop = targetPosition
    updateScrollbar()
  } else {
    // 平滑滚动动画
    const startPosition = container.scrollTop
    const distance = targetPosition - startPosition
    const startTime = performance.now()

    const animateScroll = (currentTime) => {
      const elapsed = currentTime - startTime
      const progress = Math.min(elapsed / duration, 1)

      // 使用缓动函数
      const easeInOutQuad = progress < 0.5
        ? 2 * progress * progress
        : 1 - Math.pow(-2 * progress + 2, 2) / 2

      container.scrollTop = startPosition + distance * easeInOutQuad
      updateScrollbar()

      if (progress < 1) {
        requestAnimationFrame(animateScroll)
      }
    }

    requestAnimationFrame(animateScroll)
  }
}

// 将滚动位置设置为总滚动大小的百分比
const setScrollPercentage = (percentage, duration = 0) => {
  if (!scrollContainer.value) return

  const container = scrollContainer.value
  const clampedPercentage = Math.max(0, Math.min(1, percentage))
  const maxScrollTop = container.scrollHeight - container.clientHeight
  const targetPosition = maxScrollTop * clampedPercentage

  setScrollPosition(targetPosition, duration)
}

// 获取当前滚动位置
const getScrollPosition = () => {
  return scrollContainer.value ? scrollContainer.value.scrollTop : 0
}

// 获取当前滚动百分比
const getScrollPercentage = () => {
  if (!scrollContainer.value) return 0

  const container = scrollContainer.value
  const maxScrollTop = container.scrollHeight - container.clientHeight

  if (maxScrollTop <= 0) return 0

  return container.scrollTop / maxScrollTop
}

// 滚动到顶部
const scrollToTop = (duration = 300) => {
  setScrollPosition(0, duration)
}

// 滚动到底部
const scrollToBottom = (duration = 300) => {
  if (!scrollContainer.value) return

  const container = scrollContainer.value
  const maxScrollTop = container.scrollHeight - container.clientHeight
  setScrollPosition(maxScrollTop, duration)
}

// 强制更新滚动条状态
const forceUpdateScrollbar = async () => {
  await nextTick()
  updateScrollbar()
}

onMounted(() => {
  if (scrollContainer.value) {
    // 初始化滚动条
    updateScrollbar()
  }
})

// 监听路由变化
watch(() => route.path, () => {
  // 路由变化时延迟更新滚动条状态
  setTimeout(() => {
    forceUpdateScrollbar()
  }, 100)
}, { immediate: false })

// 组件卸载时清理
onUnmounted(() => {
  // 清理工作
})

// 暴露方法给父组件
defineExpose({
  setScrollPosition,
  setScrollPercentage,
  getScrollPosition,
  getScrollPercentage,
  scrollToTop,
  scrollToBottom,
  updateScrollbar
})
</script>

<style scoped>
.custom-scroll-container {
  position: relative;
  overflow-y: auto;
  overflow-x: hidden;
  /* 隐藏默认滚动条 */
  -ms-overflow-style: none;
  scrollbar-width: none;
}

.custom-scroll-container::-webkit-scrollbar {
  display: none !important;
}

.custom-scroll-container::-webkit-scrollbar-track,
.custom-scroll-container::-webkit-scrollbar-thumb,
.custom-scroll-container::-webkit-scrollbar-button,
.custom-scroll-container::-webkit-scrollbar-corner,
.custom-scroll-container::-webkit-scrollbar-track-piece {
  display: none !important;
}

/* 自定义滚动条轨道 */
.custom-scroll-container::after {
  content: '';
  position: fixed;
  top: var(--top-offset);
  right: 0;
  width: var(--scrollbar-width);
  height: calc(100vh - var(--top-offset));
  background: var(--track-color);
  border-radius: calc(var(--scrollbar-width) / 2);
  z-index: 5998;
  pointer-events: none;
  opacity: var(--scrollbar-visible);
  transition: opacity 0.3s ease;
}

/* 自定义滚动条滑块 */
.custom-scroll-container::before {
  content: '';
  position: fixed;
  top: var(--thumb-top);
  right: 0;
  width: var(--scrollbar-width);
  height: var(--thumb-height);
  background: var(--thumb-color);
  border-radius: calc(var(--scrollbar-width) / 2);
  z-index: 5999;
  transition: background 0.3s ease, opacity 0.3s ease;
  pointer-events: auto;
  cursor: pointer;
  opacity: var(--scrollbar-visible);
}

.custom-scroll-container:hover::before {
  background: var(--thumb-hover-color);
}
</style>