<template>
  <div class="wrapper relative w-full h-[100vh] bg-[#Fdfbf7] overflow-hidden text-[#2c2c2c]">

    <!-- 入场揭幕帘幕（雅致双开门 + 徽标） -->
    <div v-show="showIntro" class="curtain-root" :class="{ 'is-opening': introOpening }" @click="openInvitation">
      <div class="curtain-bg" :style="curtainBg"></div>
      <div class="curtain-veil"></div>
      <div class="curtain-door curtain-door-left"><span class="door-sheen"></span></div>
      <div class="curtain-door curtain-door-right"><span class="door-sheen"></span></div>
      <div class="curtain-emblem">
        <div class="emblem-inner">
          <span class="emblem-floral">❀</span>
          <span class="emblem-kicker">WEDDING INVITATION</span>
          <div class="emblem-names">{{ data.groom }}<span class="amp">&amp;</span>{{ data.bride }}</div>
          <div class="emblem-rule"></div>
          <div class="emblem-date">{{ data.date }}</div>
          <div class="emblem-hint"><span class="dot"></span>轻触开启请柬</div>
        </div>
      </div>
    </div>

    <!-- 背景柔光层（淡金/淡粉光斑，缓慢漂移） -->
    <div class="bg-glow" aria-hidden="true"><i class="g1"></i><i class="g2"></i><i class="g3"></i></div>

    <!-- 飘落花瓣层（外层位移 + 内层摇曳，全 transform 不触发布局） -->
    <div v-if="data.petalEnabled" class="absolute inset-0 pointer-events-none overflow-hidden z-[1]">
      <div v-for="p in petals" :key="'p'+p.id" class="petal"
           :style="{ left: p.left, width: p.size+'px', height: p.size+'px', opacity: p.opacity, animationDelay: p.delay, '--p-dur': p.duration }">
        <svg viewBox="0 0 100 100" class="petal-inner" :style="{ '--p-sway': p.sway, filter: p.filter }">
          <path d="M50 3 C28 26 20 62 50 97 C80 62 72 26 50 3 Z" :fill="p.color" opacity="0.9" />
          <path d="M50 9 C50 36 50 70 50 91" stroke="rgba(255,255,255,0.55)" stroke-width="1.4" fill="none" opacity="0.5" />
        </svg>
      </div>
    </div>

    <!-- 漂浮爱心层（三层景深：远小淡模糊 / 近大清晰） -->
    <div v-if="data.bubbleEnabled" class="absolute inset-0 pointer-events-none overflow-hidden z-[1]">
      <div v-for="b in bubbles" :key="'b'+b.id"
           class="heart-bubble flex items-center justify-center"
           :style="{ left: b.left, top: b.top, color: b.color, fontSize: b.size+'px', animationDelay: b.delay, '--float-duration': b.floatDuration, '--h-opacity': b.opacity }">
        <span class="heart-inner" :style="{ '--sway-duration': b.swayDuration, filter: b.filter }">♥</span>
      </div>
    </div>

    <!-- 顶部滚动进度条 -->
    <div class="absolute top-0 left-0 h-[2px] bg-[#a88c6b] z-[55] transition-[width] duration-150" :style="{ width: progress * 100 + '%' }"></div>

    <!-- 右上角控制台 -->
    <div class="absolute top-6 right-5 z-50 flex flex-col items-end gap-4">
      <!-- 音乐控制 -->
      <div class="music-wrap">
        <div class="flex flex-col gap-3 items-end">
          <div @click="audio.toggle()" class="control-btn cursor-pointer" :class="{ 'rotate-spin': audio.isPlaying.value }">
            <img v-if="audio.isPlaying.value" src="https://api.iconify.design/lucide:music.svg?color=%23a88c6b" class="w-4 h-4" />
            <img v-else src="https://api.iconify.design/lucide:volume-x.svg?color=%23a88c6b" class="w-4 h-4" />
          </div>
          <div v-if="audio.tracks.value.length > 1" @click="showTrackList = !showTrackList" class="control-btn cursor-pointer">
            <img src="https://api.iconify.design/lucide:list-music.svg?color=%23a88c6b" class="w-4 h-4" />
          </div>
        </div>
        <!-- 曲目切换弹层 -->
        <div v-if="showTrackList && audio.tracks.value.length" class="track-pop">
          <div class="track-pop-title">选择曲目</div>
          <div v-for="t in audio.tracks.value" :key="t.url"
               class="track-item" :class="{ active: t.url === audio.activeUrl.value }"
               @click="selectTrack(t.url)">
            <span class="eq" v-if="t.url === audio.activeUrl.value && audio.isPlaying.value"><i></i><i></i><i></i></span>
            <span class="tname">{{ t.name }}</span>
            <span class="tcheck" v-if="t.url === audio.activeUrl.value">✓</span>
          </div>
        </div>
      </div>

      <div @click="toggleAutoScroll" class="control-btn cursor-pointer transition-all duration-300"
           :class="isAutoScroll ? 'bg-[#a88c6b]/15 !border-[#a88c6b]/60 shadow-sm' : 'bg-white/60 shadow-sm border-[#a88c6b]/30'">
        <img v-if="isAutoScroll" src="https://api.iconify.design/lucide:pause.svg?color=%23a88c6b" class="w-4 h-4" />
        <img v-else src="https://api.iconify.design/lucide:play.svg?color=%23a88c6b" class="w-4 h-4 ml-0.5" />
      </div>
    </div>

    <!-- 主滚动区域（注意：不要加 scroll-smooth，它会劫持 JS 滚动赋值导致卡顿） -->
    <div ref="scrollContainerRef"
         class="w-full h-full overflow-y-auto no-scrollbar relative"
         :class="data.scrollMode === 'snap' ? 'snap-y snap-mandatory' : ''"
         @scroll="handleScroll" @touchstart="handleUserInteraction" @touchmove="handleUserInteraction"
         @wheel="handleUserInteraction" @mousedown="handleUserInteraction">

      <!-- 1. 封面页 -->
      <div class="page-section" :class="data.scrollMode === 'snap' ? 'snap-start' : ''">
        <div class="flex flex-col items-center justify-between py-12 h-full w-full relative border-[0.5px] border-[#a88c6b]/20 bg-white/40">
          <div v-reveal="'down'" class="text-center mt-6 z-10">
            <span class="text-[10px] tracking-[0.5em] uppercase text-[#a88c6b] font-light block">Wedding Invitation</span>
            <div class="w-6 h-[0.5px] bg-[#a88c6b] mx-auto opacity-50 mt-4"></div>
          </div>

          <div v-reveal="{ variant: 'scale', delay: 120 }" class="w-full max-w-[260px] aspect-[3/4] relative z-10">
            <div class="absolute inset-0 border border-[#a88c6b] translate-x-3 translate-y-3 opacity-30"></div>
            <div class="relative w-full h-full z-10 bg-[#F7F6F2] shadow-md overflow-hidden">
              <img :src="data.heroImg" class="w-full h-full object-cover will-change-transform" :style="{ transform: `translateY(${parallax}px) scale(1.12)` }" />
            </div>
          </div>

          <div v-reveal="{ variant: 'up', delay: 200 }" class="text-center z-10 mb-10 space-y-4 px-4">
            <div class="flex items-end justify-center gap-6 text-3xl font-light tracking-[0.2em]">
              <span>{{ data.groom }}</span>
              <span class="text-[#a88c6b] text-xl pb-1 italic font-serif">&amp;</span>
              <span>{{ data.bride }}</span>
            </div>
            <div class="flex flex-col items-center text-[11px] text-[#8A8680] tracking-[0.2em] mt-4 uppercase">
              <span>{{ data.date }}</span>
              <div class="w-4 h-[0.5px] bg-[#a88c6b]/40 my-2"></div>
              <span>{{ data.lunar }}</span>
            </div>
          </div>
        </div>
      </div>

      <!-- 2. 竖排文案页 -->
      <div class="page-section bg-[#F7F6F2] items-center px-8 relative justify-center" :class="data.scrollMode === 'snap' ? 'snap-start' : ''">
        <div class="absolute top-0 left-0 w-32 h-32 border-l-[0.5px] border-t-[0.5px] border-[#a88c6b]/30 m-6"></div>
        <div class="absolute bottom-0 right-0 w-32 h-32 border-r-[0.5px] border-b-[0.5px] border-[#a88c6b]/30 m-6"></div>
        <div v-reveal="'blur'" class="flex flex-col items-center w-full">
          <div class="text-3xl opacity-60 mb-14 text-[#a88c6b] font-serif float-soft">❀</div>
          <div class="flex justify-center gap-10 h-72 text-[#3A3A3A] text-lg leading-loose font-light">
            <span class="vertical-text">{{ data.formalText1 }}</span>
            <span class="vertical-text" style="padding-top: 3rem;">{{ data.formalText2 }}</span>
            <span class="vertical-text text-[#8A8680] text-[12px] ml-4 border-l-[0.5px] border-[#a88c6b]/30 pl-6 h-56 mt-8 tracking-[0.3em]">诚挚邀请您见证我们的幸福</span>
          </div>
        </div>
      </div>

      <!-- 3-N. 画廊循环 -->
      <div v-for="(page, pIdx) in data.photoPages" :key="pIdx" class="page-section p-6 relative" :class="data.scrollMode === 'snap' ? 'snap-start' : ''" :style="pageHeightStyle(page)">
        <div class="absolute inset-0 bg-white/40 backdrop-blur-[2px] -z-10"></div>
        <div class="absolute top-0 left-0 w-24 h-24 border-l-[0.5px] border-t-[0.5px] border-[#a88c6b]/30 m-6 pointer-events-none z-0"></div>
        <div class="absolute bottom-0 right-0 w-24 h-24 border-r-[0.5px] border-b-[0.5px] border-[#a88c6b]/30 m-6 pointer-events-none z-0"></div>
        <div class="w-full h-full flex flex-col justify-center py-6 relative z-10">
          <PhotoGallery :page="page" />
        </div>
      </div>

      <!-- 婚礼流程 -->
      <div class="page-section bg-transparent px-6 z-10 justify-center relative" :class="data.scrollMode === 'snap' ? 'snap-start' : ''">
        <div class="absolute inset-0 bg-[#Fdfbf7]/60 backdrop-blur-[2px] -z-10"></div>
        <div v-reveal="'up'" class="text-center mb-14">
          <span class="text-2xl text-[#a88c6b] tracking-[0.3em] font-light block">婚礼流程</span>
          <span class="text-[10px] text-[#8A8680] font-sans uppercase tracking-[0.4em] mt-3 block">Wedding Schedule</span>
        </div>
        <div class="relative w-full px-2 max-w-[340px] mx-auto">
          <div class="absolute left-1/2 top-2 bottom-4 w-[0.5px] bg-[#a88c6b]/40 -translate-x-1/2"></div>
          <div v-for="(item, index) in data.schedule" :key="index" class="flex w-full mb-10 relative z-10" :class="index % 2 === 0 ? 'justify-start' : 'justify-end'">
            <div v-reveal="{ variant: index % 2 === 0 ? 'left' : 'right', delay: index * 120 }"
                 class="w-[45%] flex flex-col relative bg-white/60 p-4 rounded-xl shadow-sm border-[0.5px] border-[#a88c6b]/10"
                 :class="index % 2 === 0 ? 'text-right items-end' : 'text-left items-start'">
              <div class="absolute top-[22px] w-2 h-2 rounded-full bg-[#a88c6b] shadow-[0_0_0_4px_rgba(168,140,107,0.15)]" :class="index % 2 === 0 ? '-right-[28px]' : '-left-[28px]'"></div>
              <span class="text-xl font-serif text-[#a88c6b] mb-1 font-light tracking-wider">{{ item.time }}</span>
              <span class="text-[13px] tracking-[0.2em] text-[#3a3a3a] font-medium mb-1">{{ item.event }}</span>
              <span class="text-[9px] tracking-[0.1em] text-[#8A8680] font-sans uppercase">{{ item.desc }}</span>
            </div>
          </div>
        </div>
      </div>

      <!-- 尾页 -->
      <div class="page-section ending-page px-6 py-8 flex flex-col items-center justify-center relative" :class="data.scrollMode === 'snap' ? 'snap-start' : ''">
        <div class="ending-frame" aria-hidden="true"></div>
        <div class="ending-corners" aria-hidden="true"><i></i><i></i></div>
        <div class="w-full max-w-[340px] flex flex-col items-center z-10 relative">
          <div v-reveal="'down'" class="ending-kicker">
            <span>With Love</span>
            <i></i>
          </div>
          <div v-reveal="{ variant: 'scale', delay: 100 }" class="ending-photo">
            <img :src="endImage" class="w-full h-full bg-[#F7F6F2] object-cover" alt="婚礼尾页照片" />
          </div>
          <div v-reveal="{ variant: 'up', delay: 180 }" class="ending-copy">
            <span class="ending-title">期待您的光临</span>
            <span class="ending-names">{{ data.groom }} &amp; {{ data.bride }}</span>
            <span class="ending-date">{{ data.date }}</span>
          </div>
          <div v-reveal="{ variant: 'up', delay: 240 }" class="ending-venue">
            <span class="ending-hotel">{{ data.hotel }}</span>
            <span class="ending-address">{{ data.address }}</span>
          </div>
          <div v-reveal="{ variant: 'up', delay: 300 }" class="w-full max-w-[280px]">
            <button class="rsvp-cta" @click="isDrawerOpen = true">
              <span class="rsvp-cta-deco">❀</span>
              <span class="rsvp-cta-text">填写出席回执</span>
              <span class="rsvp-cta-line"></span>
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- RSVP 抽屉 -->
    <div v-if="isDrawerOpen" class="absolute inset-0 z-[60] bg-black/40 backdrop-blur-sm transition-opacity duration-500" @click="closeDrawer"></div>
    <div class="absolute bottom-0 left-0 w-full bg-white rounded-t-[2.5rem] shadow-2xl transition-transform duration-500 z-[70] p-10 flex flex-col" :style="{ transform: isDrawerOpen ? 'translateY(0)' : 'translateY(100%)' }">
      <div @click="closeDrawer" class="absolute top-6 right-6 p-2 text-[#a88c6b] cursor-pointer hover:text-[#2c2c2c] transition-colors text-xl">✕</div>
      <span class="text-xl text-center text-[#a88c6b] mb-1 tracking-[0.3em] font-light mt-2">出席回执</span>
      <span class="text-center text-[10px] text-[#8A8680] mb-10 tracking-[0.4em]">敬 请 回 复</span>

      <div v-if="!isSubmitted" class="space-y-6">
        <div>
          <span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest pl-1">姓名</span>
          <input v-model="rsvpForm.name" placeholder="您的姓名" class="w-full bg-[#Fdfbf7] border-[0.5px] border-[#a88c6b]/30 rounded-xl px-5 py-4 text-[13px] focus:outline-none focus:border-[#a88c6b] shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]" />
        </div>
        <div>
          <span class="block text-[10px] text-[#a88c6b] mb-2 tracking-widest pl-1">出席情况</span>
          <div class="flex flex-wrap gap-2">
            <button v-for="opt in rsvpOptions" :key="opt.value" type="button"
                    class="rsvp-tag" :class="{ active: rsvpForm.guest_count === opt.value }"
                    @click="rsvpForm.guest_count = opt.value">{{ opt.label }}</button>
          </div>
        </div>
        <div>
          <span class="block text-[10px] text-[#a88c6b] mb-1.5 tracking-widest pl-1">祝福语</span>
          <textarea v-model="rsvpForm.wishes" placeholder="写下您的祝福..." class="w-full bg-[#Fdfbf7] border-[0.5px] border-[#a88c6b]/30 rounded-xl px-5 py-4 text-[13px] h-24 focus:outline-none resize-none shadow-[inset_0_2px_4px_rgba(0,0,0,0.02)]"></textarea>
        </div>
        <div @click="handleSubmitRsvp" class="w-full bg-[#a88c6b] text-white py-4 rounded-full text-center tracking-[0.3em] text-[12px] cursor-pointer hover:bg-[#967b5c] transition-all shadow-md">确认发送</div>
      </div>
      <div v-else class="text-center py-10 flex flex-col items-center animate-fade-up">
        <span class="text-3xl text-[#a88c6b] mb-6 animate-pulse-heart">♥</span>
        <span class="text-lg text-[#2c2c2c] mb-3 tracking-[0.2em] font-light">感恩您的祝福</span>
        <span class="text-[13px] text-[#8A8680] leading-loose tracking-widest font-light">回执已妥投，期待与您共享喜悦</span>
      </div>
    </div>

  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { getConfig, submitRsvp } from '@/api/wedding'
import { useAudio } from '@/composables/useAudio'
import PhotoGallery from '@/components/PhotoGallery.vue'

const DEFAULTS = {
  scrollMode: 'snap', petalEnabled: true, bubbleEnabled: true, introEnabled: true,
  musicList: [], activeMusicUrl: '',
  freeScrollInterval: 50,    // 自由滚动速度：滚动间隔 ms（越小越快）
  pageSwitchDuration: 800,   // 页面切换速度：翻页动画时长 ms
}

const data = ref({
  groom: '李明', bride: '王华', date: '2026-05-20', lunar: '农历四月初四 星期三',
  hotel: '杭州星光万丽大酒店', address: '杭州市西湖区星光大道88号\n3楼大宴会厅',
  formalText1: '两姓联姻 一堂缔约', formalText2: '良缘永结 匹配同称',
  heroImg: 'https://images.unsplash.com/photo-1583939003579-730e3918a45a?auto=format&fit=crop&w=800&q=80',
  endImg: 'https://images.unsplash.com/photo-1519741497674-611481863552?auto=format&fit=crop&w=800&q=80',
  photoPages: [
    { type: 'single', title: '初遇', subtitle: 'FIRST MET', desc: '世界那么大，还是遇见了你。\n于千万人之中，没有早一步也没有晚一步。', img1: 'https://images.unsplash.com/photo-1606800052052-a08af7148866?auto=format&fit=crop&w=600&q=80', borderStyle: 'mat' },
    { type: 'overlap', title: '相知', subtitle: 'FALL IN LOVE', desc: '纵然万劫不复，纵然相思入骨。\n我也待你眉眼如初，岁月如故。', img1: 'https://images.unsplash.com/photo-1532712938310-34cb3982ef74?auto=format&fit=crop&w=600&q=80', img2: 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=600&q=80', borderStyle: 'mat' },
    { type: 'one-large-five-small', title: '相恋', subtitle: 'ROMANCE', desc: '星光坠入眼眸，晚风轻抚过裙摆。\n浪漫不止于此，还有无数个明天。', images: Array.from({ length: 6 }, () => 'https://images.unsplash.com/photo-1519741497674-611481863552?auto=format&fit=crop&w=600&q=80'), borderStyle: 'mat' },
    { type: 'nine-grid', title: '相守', subtitle: 'FOREVER', desc: '往后余生，风雪是你，平淡是你。', images: Array.from({ length: 9 }, () => 'https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&w=400&q=80'), borderStyle: 'mat' },
  ],
  schedule: [ { time: '16:00', event: '签到迎宾', desc: 'Welcome' }, { time: '17:08', event: '仪式开始', desc: 'Ceremony' }, { time: '18:00', event: '敬备喜宴', desc: 'Banquet' } ],
  ...DEFAULTS,
})

const audio = useAudio()
const isAutoScroll = ref(true), isDrawerOpen = ref(false), isSubmitted = ref(false)
const isInteracting = ref(false), scrollContainerRef = ref(null), progress = ref(0), parallax = ref(0)
const showIntro = ref(false), introOpening = ref(false), showTrackList = ref(false), showMusicAuth = ref(false)
const rsvpForm = reactive({ name: '', guest_count: '1', wishes: '' })
const rsvpOptions = [ { value: '1', label: '1 人出席' }, { value: '2', label: '2 人出席' }, { value: '3', label: '3 人及以上' }, { value: '0', label: '遗憾缺席' } ]

let rafId = null, snapTimer = null, pauseTimer = null, introTimer = null, freeTimer = null, animId = null

// 后台可配置的滚动参数（带默认值兜底，防止脏数据）
const freeInterval = computed(() => {
  const v = Number(data.value.freeScrollInterval)
  return v >= 10 && v <= 1000 ? v : 50
})
const switchDuration = computed(() => {
  const v = Number(data.value.pageSwitchDuration)
  return v >= 0 && v <= 5000 ? v : 800
})

// 装饰元素配色（柔化后的低饱和金粉系，与主题协调不抢眼）
const loveColors = ['#c9b08a', '#e2b3c0', '#d4af37', '#e8c9d2']
const petalColors = ['#f7dce3', '#fbeee3', '#f3c9d6', '#efdcc8', '#f9e7d6']

// 爱心三层景深：远(小/淡/模糊) 中 近(大/清晰)，营造纵深而不杂乱
const heartTiers = [
  { n: 5, size: [10, 13], opacity: [0.1, 0.16], blur: 1.6, dur: [20, 26] },   // 远景
  { n: 4, size: [14, 17], opacity: [0.16, 0.24], blur: 0.7, dur: [16, 21] },  // 中景
  { n: 3, size: [18, 22], opacity: [0.24, 0.32], blur: 0, dur: [13, 17] },    // 近景
]
let heartId = 0
const bubbles = heartTiers.flatMap((t) =>
  Array.from({ length: t.n }).map(() => {
    const id = heartId++
    return {
      id,
      left: Math.random() * 100 + '%', top: Math.random() * 100 + '%',
      color: loveColors[id % loveColors.length],
      size: t.size[0] + Math.random() * (t.size[1] - t.size[0]),
      opacity: +(t.opacity[0] + Math.random() * (t.opacity[1] - t.opacity[0])).toFixed(2),
      filter: t.blur ? `blur(${t.blur}px)` : 'none',
      floatDuration: (t.dur[0] + Math.random() * (t.dur[1] - t.dur[0])).toFixed(1) + 's',
      swayDuration: (4.5 + Math.random() * 2.5).toFixed(1) + 's',
      delay: '-' + (Math.random() * 20).toFixed(1) + 's',
    }
  })
)
// 花瓣：两层景深，远处更小更淡带轻微模糊
const petals = Array.from({ length: 16 }).map((_, i) => {
  const far = i % 3 === 0
  return {
    id: i, left: Math.random() * 100 + '%',
    size: far ? 8 + Math.random() * 7 : 13 + Math.random() * 11,
    opacity: far ? 0.3 + Math.random() * 0.15 : 0.42 + Math.random() * 0.3,
    color: petalColors[i % petalColors.length],
    filter: far ? 'blur(1.2px) drop-shadow(0 2px 3px rgba(150,110,90,0.08))' : 'drop-shadow(0 2px 3px rgba(150,110,90,0.12))',
    duration: (far ? 13 : 9) + Math.random() * 8 + 's',
    delay: (Math.random() * 10) + 's',
    sway: (4 + Math.random() * 4) + 's',
  }
})

const curtainBg = computed(() => ({ backgroundImage: `url(${data.value.heroImg})` }))
const endImage = computed(() => data.value.endImg || data.value.heroImg)

// 相册页页面高度：支持 100vh / 80vh / 60vh / auto / 自定义 vh
const pageHeightStyle = (page) => {
  const h = page.height || '100vh'
  return h === 'auto' ? { minHeight: 'auto' } : { minHeight: h }
}

const closeDrawer = () => { isDrawerOpen.value = false }
const authorizeMusic = () => { audio.play(); showMusicAuth.value = false }
audio.play()
const handleScroll = () => {
  const el = scrollContainerRef.value
  if (!el) return
  const max = el.scrollHeight - el.clientHeight
  progress.value = max > 0 ? el.scrollTop / max : 0
  parallax.value = el.scrollTop * 0.25
}

const handleUserInteraction = () => {
  isInteracting.value = true
  // 用户接管时立即取消程序化的翻页动画，避免与人争抢滚动
  cancelAnimationFrame(animId)
  clearTimeout(pauseTimer)
  pauseTimer = setTimeout(() => (isInteracting.value = false), 3000)
}

const sectionEls = () => Array.from(scrollContainerRef.value?.querySelectorAll('.page-section') || [])

// 带时长的平滑滚动（easeInOutQuad），duration 由后台 pageSwitchDuration 控制
const smoothScrollTo = (el, target, duration) => {
  cancelAnimationFrame(animId)
  const start = el.scrollTop, dist = target - start
  if (!dist) return
  if (duration <= 0) { el.scrollTop = target; return }
  const t0 = performance.now()
  const tick = (now) => {
    const p = Math.min(1, (now - t0) / duration)
    const e = p < 0.5 ? 2 * p * p : 1 - Math.pow(-2 * p + 2, 2) / 2
    el.scrollTop = start + dist * e
    if (p < 1) animId = requestAnimationFrame(tick)
  }
  animId = requestAnimationFrame(tick)
}

const goNextSection = () => {
  const el = scrollContainerRef.value
  if (!el) return
  const top = el.scrollTop
  const next = sectionEls().find((e) => e.offsetTop > top + 12)
  // 循环逻辑：滚到最后一屏后回到第一屏继续轮播
  smoothScrollTo(el, next ? next.offsetTop : 0, switchDuration.value)
}

const startAutoScroll = () => {
  if (data.value.scrollMode === 'snap') {
    snapTimer = setInterval(() => {
      if (isAutoScroll.value && !isInteracting.value && !isDrawerOpen.value) goNextSection()
    }, 4500)
  } else {
    // 自由滚动：setInterval 按后台配置的间隔匀速推进（间隔越小越快）
    freeTimer = setInterval(() => {
      const el = scrollContainerRef.value
      if (el && isAutoScroll.value && !isInteracting.value && !isDrawerOpen.value) {
        el.scrollTop += 1.2
        if (el.scrollTop >= el.scrollHeight - el.clientHeight - 5) el.scrollTop = 0
      }
    }, freeInterval.value)
  }
}

const toggleAutoScroll = () => {
  isAutoScroll.value = !isAutoScroll.value
  const el = scrollContainerRef.value
  if (isAutoScroll.value && el && el.scrollTop >= el.scrollHeight - el.clientHeight - 10) el.scrollTop = 0
}

// 入场揭幕：开门动画
const openInvitation = () => {
  if (introOpening.value) return
  introOpening.value = true
  introTimer = setTimeout(() => { showIntro.value = false }, 1000)
  // 点击揭幕是明确的用户手势：直接尝试播放背景音乐（最可靠的自动播放路径）
  if (data.value.musicList.length) audio.play()
}
const onMusicAuthSkip = () => {
  showMusicAuth.value = false
  // 用户暂不开启：挂起首次交互解锁，后续任意点击仍可播放
  audio.armAutoplay()
}
const selectTrack = (url) => { audio.setActive(url); showTrackList.value = false }

const handleSubmitRsvp = async () => {
  if (!rsvpForm.name.trim()) return alert('请填写姓名')
  try {
    const res = await submitRsvp(rsvpForm)
    if (res.code === 200) isSubmitted.value = true
    else alert(res.error || '提交失败')
  } catch (e) { alert('提交失败，请检查后端运行状态') }
}

onMounted(async () => {
  try {
    const res = await getConfig()
    if (res.data && res.data !== '{}') {
      const loaded = typeof res.data === 'string' ? JSON.parse(res.data) : res.data
      // 兼容旧版单链接 musicUrl
      if (loaded.musicUrl && !(loaded.musicList && loaded.musicList.length)) {
        loaded.musicList = [{ url: loaded.musicUrl, name: '背景音乐' }]
        loaded.activeMusicUrl = loaded.musicUrl
      }
      loaded.endImg = loaded.endImg || loaded.heroImg || data.value.endImg
      data.value = { ...data.value, ...DEFAULTS, ...loaded }
    }
  } catch (e) { /* 使用默认配置 */ }

  audio.setTracks(data.value.musicList, data.value.activeMusicUrl)
  // 先静默尝试自动播放；被浏览器拦截（无用户手势）时，再弹出授权模态框
  if (data.value.musicList.length) {
    const autoOk = await audio.attemptAutoplay()
    if (!autoOk) showMusicAuth.value = true
  }
  if (data.value.introEnabled) {
    showIntro.value = true
    introTimer = setTimeout(() => openInvitation(), 3600)
  }

  startAutoScroll()
  handleScroll()
})

onUnmounted(() => {
  cancelAnimationFrame(rafId)
  cancelAnimationFrame(animId)
  clearInterval(snapTimer)
  clearInterval(freeTimer)
  clearTimeout(pauseTimer)
  clearTimeout(introTimer)
})
</script>

<style scoped>
.wrapper { font-family: "PingFang SC", sans-serif; }
.control-btn {
  width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; border-radius: 9999px;
  backdrop-filter: blur(12px); border: 0.5px solid rgba(168, 140, 107, 0.3); color: #a88c6b; background: rgba(255,255,255,0.6);
}
.vertical-text { writing-mode: vertical-rl; letter-spacing: 0.4em; text-orientation: upright; }
.page-section { min-height: 100vh; width: 100%; position: relative; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
.no-scrollbar::-webkit-scrollbar { display: none; }
/* 花瓣形状由 SVG 决定，无需额外形状样式 */

/* ---------- 入场揭幕（雅致象牙金） ---------- */
.curtain-root { position: fixed; inset: 0; z-index: 100; overflow: hidden; cursor: pointer; font-family: "PingFang SC", sans-serif; background: #fbf6ef; }
.curtain-bg {
  position: absolute; inset: -24px; background-size: cover; background-position: center;
  filter: blur(16px) brightness(0.7) saturate(1.05); transform: scale(1.12);
}
.curtain-veil { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(251,246,239,0.35), rgba(232,214,194,0.25)); }
.curtain-door {
  position: absolute; top: 0; bottom: 0; width: 50%; z-index: 2;
  background: linear-gradient(160deg, #fbf6ef 0%, #f5e9dc 45%, #ecd9c4 100%);
  box-shadow: inset 0 0 50px rgba(184,154,120,0.12);
  transition: transform 1.4s cubic-bezier(0.76, 0, 0.24, 1);
}
.curtain-door::before { content: ''; position: absolute; top: 0; bottom: 0; width: 1px; background: linear-gradient(180deg, transparent, rgba(184,154,120,0.5), transparent); }
.curtain-door-left { left: 0; }
.curtain-door-right { right: 0; }
.curtain-door-left::before { right: 0; }
.curtain-door-right::before { left: 0; }
.door-sheen { position: absolute; inset: 0; background: linear-gradient(115deg, rgba(255,255,255,0.5) 0%, rgba(255,255,255,0) 30%, rgba(255,255,255,0) 70%, rgba(255,255,255,0.25) 100%); }
.curtain-root.is-opening .curtain-door-left { transform: translateX(-100%); }
.curtain-root.is-opening .curtain-door-right { transform: translateX(100%); }
.curtain-emblem {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 3;
  transition: opacity 0.8s ease, transform 0.9s ease; animation: emblemIn 1.1s ease both;
}
.curtain-root.is-opening .curtain-emblem { opacity: 0; transform: scale(1.25); }
.emblem-inner { text-align: center; color: #5b4a36; padding: 10px; }
.emblem-floral { display: block; font-size: 22px; color: #b89a78; margin-bottom: 14px; }
.emblem-kicker { display: block; letter-spacing: 0.6em; font-size: 9px; color: #b89a78; text-transform: uppercase; margin-bottom: 18px; padding-left: 0.6em; }
.emblem-names { font-family: "Noto Serif SC", serif; font-size: 30px; letter-spacing: 0.18em; font-weight: 300; color: #4a3f30; }
.emblem-names .amp { font-style: italic; color: #b89a78; margin: 0 8px; }
.emblem-rule { width: 46px; height: 1px; background: linear-gradient(90deg, transparent, #b89a78, transparent); margin: 18px auto; }
.emblem-date { font-size: 11px; letter-spacing: 0.3em; color: #8a7458; }
.emblem-hint { margin-top: 26px; font-size: 11px; letter-spacing: 0.3em; color: #a08a66;
  display: flex; align-items: center; justify-content: center; gap: 8px; }
.emblem-hint .dot { width: 6px; height: 6px; border-radius: 9999px; background: #b89a78; animation: hintPulse 1.6s infinite; }

/* ---------- 尾页 ---------- */
.ending-page {
  background:
    linear-gradient(180deg, rgba(253,251,247,0.92) 0%, rgba(247,246,242,0.98) 100%),
    radial-gradient(circle at 50% 12%, rgba(232,201,210,0.2), transparent 34%);
}
.ending-frame {
  position: absolute; top: 28px; right: 22px; bottom: 28px; left: 22px;
  border: 1px solid rgba(168,140,107,0.26); border-radius: 160px 160px 24px 24px;
  background: rgba(255,255,255,0.28); pointer-events: none;
}
.ending-frame::before {
  content: ''; position: absolute; inset: 9px;
  border: 0.5px solid rgba(168,140,107,0.18); border-radius: 150px 150px 18px 18px;
}
.ending-corners i {
  position: absolute; width: 54px; height: 54px; border-color: rgba(168,140,107,0.28);
}
.ending-corners i:first-child { top: 44px; left: 38px; border-top: 1px solid; border-left: 1px solid; }
.ending-corners i:last-child { right: 38px; bottom: 44px; border-right: 1px solid; border-bottom: 1px solid; }
.ending-kicker {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  margin-bottom: 18px; color: #a88c6b; font-size: 10px; letter-spacing: 0.45em;
  text-transform: uppercase; padding-left: 0.45em;
}
.ending-kicker i {
  display: block; width: 34px; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(168,140,107,0.75), transparent);
}
.ending-photo {
  width: min(54vw, 188px); aspect-ratio: 3 / 4; overflow: hidden;
  border-radius: 9999px 9999px 16px 16px; border: 5px solid rgba(255,255,255,0.86);
  box-shadow: 0 18px 42px rgba(100,78,48,0.18), 0 0 0 1px rgba(168,140,107,0.18);
  background: #F7F6F2;
}
.ending-copy {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  margin-top: 22px; margin-bottom: 18px; padding: 0 12px;
}
.ending-title {
  display: block; color: #a88c6b; font-size: 20px; line-height: 1.3;
  letter-spacing: 0.28em; padding-left: 0.28em; font-weight: 300;
}
.ending-names {
  display: block; margin-top: 10px; color: #3A3A3A; font-size: 14px;
  letter-spacing: 0.16em; font-family: "Noto Serif SC", serif;
}
.ending-date {
  display: block; margin-top: 8px; color: #8A8680; font-size: 10px;
  letter-spacing: 0.28em; padding-left: 0.28em;
}
.ending-venue {
  width: 100%; margin-bottom: 24px; padding: 14px 18px;
  border-top: 1px solid rgba(168,140,107,0.18);
  border-bottom: 1px solid rgba(168,140,107,0.18);
  text-align: center; background: rgba(255,255,255,0.32);
}
.ending-hotel {
  display: block; color: #3A3A3A; font-size: 13px; line-height: 1.6;
  letter-spacing: 0.18em; font-weight: 500;
}
.ending-address {
  display: block; max-width: 260px; margin: 7px auto 0; color: #706b64;
  font-size: 11px; line-height: 1.8; letter-spacing: 0.08em; white-space: pre-wrap;
}

/* ---------- 回执 CTA 按钮 ---------- */
.rsvp-cta {
  position: relative; width: 100%; padding: 16px 0; border-radius: 9999px;
  border: 1px solid #c9a978; background: rgba(255,255,255,0.6);
  color: #8a704f; font-size: 12px; letter-spacing: 0.28em; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  backdrop-filter: blur(8px); transition: all .35s ease;
  box-shadow: 0 6px 18px rgba(184,154,120,0.12);
}
.rsvp-cta:hover { background: #a88c6b; color: #fff; border-color: #a88c6b; box-shadow: 0 10px 26px rgba(184,154,120,0.28); }
.rsvp-cta-deco { font-size: 13px; opacity: .9; }
.rsvp-cta-line { width: 18px; height: 1px; background: currentColor; opacity: .6; }

/* ---------- 出席情况单选标签 ---------- */
.rsvp-tag {
  flex: 1 1 auto; min-width: 72px; padding: 10px 12px; border-radius: 12px;
  border: 1px solid rgba(168,140,107,0.35); background: #Fdfbf7; color: #6b6863;
  font-size: 12px; letter-spacing: 0.1em; cursor: pointer; transition: all .25s ease;
}
.rsvp-tag:hover { border-color: #a88c6b; }
.rsvp-tag.active { background: #a88c6b; border-color: #a88c6b; color: #fff; box-shadow: 0 4px 12px rgba(168,140,107,0.25); }

/* ---------- 音乐授权模态框 ---------- */
.music-auth-card { width: 240px; background: #fff; border-radius: 22px; padding: 28px 24px 22px; text-align: center;
  box-shadow: 0 24px 60px rgba(0,0,0,0.28); border: 1px solid rgba(168,140,107,0.2); }
.music-auth-note { font-size: 26px; color: #a88c6b; margin-bottom: 12px; }
.music-auth-title { font-size: 16px; color: #4a3f30; letter-spacing: 0.2em; margin-bottom: 6px; }
.music-auth-sub { font-size: 11px; color: #8A8680; letter-spacing: 0.15em; margin-bottom: 20px; }
.music-auth-btn { width: 100%; padding: 11px 0; border-radius: 9999px; background: #a88c6b; color: #fff;
  font-size: 12px; letter-spacing: 0.2em; cursor: pointer; border: none; transition: background .3s; }
.music-auth-btn:hover { background: #967b5c; }
.music-auth-skip { margin-top: 10px; background: none; border: none; color: #b0a99e; font-size: 11px; letter-spacing: 0.1em; cursor: pointer; }

/* ---------- 音乐曲目弹层 ---------- */
.music-wrap { position: relative; }
.track-pop {
  position: absolute; right: 0; bottom: 50px; width: 200px; background: rgba(255,255,255,0.95);
  border: 1px solid rgba(168,140,107,0.25); border-radius: 14px; box-shadow: 0 12px 30px rgba(0,0,0,0.18);
  padding: 8px; backdrop-filter: blur(12px); z-index: 60;
}
.track-pop-title { font-size: 10px; color: #a88c6b; letter-spacing: 0.2em; padding: 4px 8px 6px; }
.track-item { display: flex; align-items: center; gap: 8px; padding: 8px; border-radius: 10px; cursor: pointer; transition: background 0.2s; }
.track-item:hover { background: rgba(168,140,107,0.1); }
.track-item.active { background: rgba(168,140,107,0.16); color: #a88c6b; }
.track-item .tname { font-size: 12px; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.track-item .tcheck { font-size: 12px; color: #a88c6b; }
.eq { display: inline-flex; align-items: flex-end; gap: 2px; width: 14px; }
.eq i { width: 3px; background: #a88c6b; border-radius: 2px; animation: eqJump 0.9s ease-in-out infinite; }
.eq i:nth-child(1) { height: 8px; animation-delay: 0s; }
.eq i:nth-child(2) { height: 12px; animation-delay: 0.2s; }
.eq i:nth-child(3) { height: 6px; animation-delay: 0.4s; }
@keyframes eqJump { 0%,100% { transform: scaleY(0.4); } 50% { transform: scaleY(1); } }

@keyframes emblemIn { from { opacity: 0; transform: scale(0.85) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
@keyframes hintPulse { 0%,100% { transform: scale(1); opacity: 0.6; } 50% { transform: scale(1.7); opacity: 1; } }
</style>
