<template>
  <div class="fullpage-container" @wheel.prevent="handleWheel" @touchstart="handleTouchStart"
    @touchend="handleTouchEnd">
    <div class="fullpage-wrapper" :style="wrapperStyle">
      <slot />
    </div>
    <div class="fullpage-dots">
      <span v-for="i in pageCount" :key="i" class="dot" :class="{ active: currentIndex === i - 1 }"
        @click="goTo(i - 1)">
        <span class="dot-inner" />
      </span>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, useSlots, watch, nextTick } from 'vue'

const slots = useSlots()
const pageCount = computed(() => {
  const defaultSlot = slots.default?.()
  return defaultSlot ? defaultSlot.length : 0
})

const currentIndex = ref(0)
const isAnimating = ref(false)
const touchStartY = ref(0)
const direction = ref('down')

const wrapperStyle = computed(() => ({
  transform: `translateY(-${currentIndex.value * 100}vh)`,
  transition: isAnimating.value ? 'transform 0.9s cubic-bezier(0.76, 0, 0.24, 1)' : 'none',
}))

function goTo(index) {
  if (isAnimating.value || index === currentIndex.value) return
  if (index < 0 || index >= pageCount.value) return
  direction.value = index > currentIndex.value ? 'down' : 'up'
  isAnimating.value = true
  currentIndex.value = index
  triggerPageAnimation(index)
  setTimeout(() => { isAnimating.value = false }, 900)
}

function triggerPageAnimation(index) {
  nextTick(() => {
    const pages = document.querySelectorAll('.fullpage-wrapper > *')
    const page = pages[index]
    if (!page) return
    page.classList.remove('page-enter')
    void page.offsetWidth
    page.classList.add('page-enter')
  })
}

function handleWheel(e) {
  if (isAnimating.value) return
  if (e.deltaY > 0) goTo(currentIndex.value + 1)
  else if (e.deltaY < 0) goTo(currentIndex.value - 1)
}

function handleTouchStart(e) {
  touchStartY.value = e.touches[0].clientY
}

function handleTouchEnd(e) {
  const deltaY = touchStartY.value - e.changedTouches[0].clientY
  if (Math.abs(deltaY) > 50) {
    if (deltaY > 0) goTo(currentIndex.value + 1)
    else goTo(currentIndex.value - 1)
  }
}

defineExpose({ currentIndex, goTo })
</script>

<style scoped>
.fullpage-container {
  width: 100%;
  height: 100vh;
  overflow: hidden;
  position: relative;
}

.fullpage-wrapper {
  width: 100%;
  will-change: transform;
}

/* 圆点导航升级 */
.fullpage-dots {
  position: fixed;
  right: 28px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 16px;
  z-index: 100;
}

.dot {
  width: 12px;
  height: 12px;
  position: relative;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.dot::before {
  content: '';
  position: absolute;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  border: 1.5px solid rgba(0, 0, 0, 0.2);
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.dot-inner {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.25);
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  display: block;
}

.dot.active::before {
  border-color: #00BFA5;
  width: 20px;
  height: 20px;
  box-shadow: 0 0 0 3px rgba(0, 191, 165, 0.15);
}

.dot.active .dot-inner {
  width: 6px;
  height: 6px;
  background: #00BFA5;
  box-shadow: 0 0 8px rgba(0, 191, 165, 0.6);
}

/* 页面入场动画 - 仅针对非绝对定位元素 */
:global(.page-enter .text-side),
:global(.page-enter .image-side),
:global(.page-enter .content-wrapper) {
  animation: fadeSlideUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
}

:global(.page-enter .image-side) {
  animation-delay: 0.1s;
}

@keyframes fadeSlideUp {
  from {
    opacity: 0;
    transform: translateY(32px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@media (max-width: 768px) {
  .fullpage-dots {
    right: unset;
    top: unset;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    flex-direction: row;
  }
  .dot.active::before {
    width: 16px;
    height: 16px;
  }
}
</style>
