<script setup>
const route = useRoute()
const progress = ref(0)
const showBackToTop = ref(false)
let observer
let frame

function updateScrollState() {
  const scrollTop = window.scrollY || document.documentElement.scrollTop
  const scrollable = Math.max(document.documentElement.scrollHeight - window.innerHeight, 1)
  progress.value = Math.min(100, Math.max(0, (scrollTop / scrollable) * 100))
  showBackToTop.value = scrollTop > Math.min(window.innerHeight * 0.72, 620)
}

function onScroll() {
  if (frame) return
  frame = window.requestAnimationFrame(() => {
    frame = 0
    updateScrollState()
  })
}

function prepareSectionReveals() {
  observer?.disconnect()
  const page = document.querySelector(
    '.about-page, .advantages-page, .services-page, .solutions-page, .cases-page, .case-detail-page, .insights-page, .article-page'
  )
  if (!page || window.matchMedia('(prefers-reduced-motion: reduce)').matches) return

  page.classList.add('interior-reveal-ready')
  const sections = [
    ...page.querySelectorAll('main > section, main > article > div, main > article > header')
  ]
  sections.forEach((section, index) => {
    section.classList.add('interior-reveal')
    if (index === 0 || section.getBoundingClientRect().top < window.innerHeight * 0.92) {
      section.classList.add('is-revealed')
    }
  })

  observer = new IntersectionObserver(
    (entries) => {
      entries.forEach((entry) => {
        if (!entry.isIntersecting) return
        entry.target.classList.add('is-revealed')
        observer?.unobserve(entry.target)
      })
    },
    { rootMargin: '0px 0px -9% 0px', threshold: 0.08 }
  )

  sections
    .filter((section) => !section.classList.contains('is-revealed'))
    .forEach((section) => observer.observe(section))
}

function backToTop() {
  window.scrollTo({ top: 0, behavior: 'smooth' })
}

onMounted(async () => {
  window.addEventListener('scroll', onScroll, { passive: true })
  window.addEventListener('resize', onScroll, { passive: true })
  await nextTick()
  updateScrollState()
  prepareSectionReveals()
})

watch(
  () => route.fullPath,
  async () => {
    await nextTick()
    updateScrollState()
    prepareSectionReveals()
  }
)

onBeforeUnmount(() => {
  observer?.disconnect()
  if (frame) window.cancelAnimationFrame(frame)
  window.removeEventListener('scroll', onScroll)
  window.removeEventListener('resize', onScroll)
})
</script>

<template>
  <div class="reading-progress" aria-hidden="true">
    <span :style="{ transform: `scaleX(${progress / 100})` }"></span>
  </div>
  <Transition name="back-top">
    <button
      v-if="showBackToTop"
      class="back-to-top"
      type="button"
      aria-label="回到页面顶部"
      title="回到顶部"
      @click="backToTop"
    >
      <AppIcon name="bottom" />
    </button>
  </Transition>
</template>

<style scoped>
.reading-progress {
  position: fixed;
  z-index: 45;
  top: 0;
  right: 0;
  left: 0;
  height: 2px;
  pointer-events: none;
}
.reading-progress span {
  width: 100%;
  height: 100%;
  display: block;
  background: linear-gradient(90deg, #166ff3, #62c8f1);
  box-shadow: 0 1px 8px rgba(27, 124, 240, 0.34);
  transform-origin: left center;
  will-change: transform;
}
.back-to-top {
  position: fixed;
  z-index: 28;
  right: clamp(18px, 2.7vw, 42px);
  bottom: clamp(18px, 3vw, 40px);
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(91, 151, 224, 0.22);
  border-radius: 6px;
  color: #2379e8;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 14px 34px rgba(37, 94, 160, 0.16);
  backdrop-filter: blur(14px);
  transition:
    color 0.22s ease,
    background 0.22s ease,
    transform 0.22s ease,
    box-shadow 0.22s ease;
}
.back-to-top :deep(.app-icon) {
  width: 18px;
  height: 18px;
  transform: rotate(180deg);
}
.back-to-top:hover {
  color: #fff;
  background: #207bf2;
  box-shadow: 0 17px 36px rgba(31, 121, 236, 0.25);
  transform: translateY(-3px);
}
.back-to-top:active {
  transform: translateY(1px) scale(0.97);
}
.back-top-enter-active,
.back-top-leave-active {
  transition:
    opacity 0.2s ease,
    transform 0.24s ease;
}
.back-top-enter-from,
.back-top-leave-to {
  opacity: 0;
  transform: translateY(12px);
}
@media (max-width: 680px) {
  .back-to-top {
    right: 16px;
    bottom: 16px;
    width: 42px;
    height: 42px;
  }
}
</style>
