<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import type { BannerItem } from '../BannerCarousel.vue';
import defaultBannerImg from '../../assets/images/banner.webp';

const props = defineProps<{
  banners: BannerItem[];
  fallbackTo?: string;
}>();

const AUTOPLAY_MS = 5500;

const { t } = useI18n();
const router = useRouter();
const active = ref(0);
const timer = ref<ReturnType<typeof setInterval> | null>(null);
const FALLBACK_IMG = '/uploads/banners/welcome.svg';

const slideCount = computed(() => props.banners.length);
const canLoop = computed(() => slideCount.value > 1);
const activeBanner = computed(() => props.banners[active.value]);

function imageUrl(banner: BannerItem) {
  return banner.translation?.imageUrl || defaultBannerImg || FALLBACK_IMG;
}

function onImgError(e: Event) {
  const img = e.target as HTMLImageElement;
  if (img.dataset.fallbackApplied) return;
  img.dataset.fallbackApplied = '1';
  img.src = defaultBannerImg || FALLBACK_IMG;
}

function title(banner: BannerItem) {
  return banner.translation?.title || t('home.banner_fallback');
}

function goTo(index: number) {
  if (!slideCount.value) return;
  active.value = (index + slideCount.value) % slideCount.value;
}

function next() {
  goTo(active.value + 1);
}

function prev() {
  goTo(active.value - 1);
}

function onBannerClick(banner: BannerItem) {
  if (banner.id) {
    void router.push(`/announcements/${banner.id}`);
    return;
  }
  if (props.fallbackTo) {
    void router.push(props.fallbackTo);
  }
}

function startAutoPlay() {
  stopAutoPlay();
  if (!canLoop.value) return;
  timer.value = setInterval(next, AUTOPLAY_MS);
}

function stopAutoPlay() {
  if (timer.value) {
    clearInterval(timer.value);
    timer.value = null;
  }
}

watch(
  () => props.banners.length,
  () => {
    active.value = 0;
    startAutoPlay();
  },
);

onMounted(startAutoPlay);
onUnmounted(stopAutoPlay);
</script>

<template>
  <section
    v-if="banners.length"
    class="hero-carousel"
    @mouseenter="stopAutoPlay"
    @mouseleave="startAutoPlay"
  >
    <div class="hero-frame">
      <div class="hero-stage">
        <button
          v-for="(banner, i) in banners"
          :key="banner.id ?? i"
          type="button"
          class="hero-slide"
          :class="{ 'is-active': i === active }"
          :aria-label="title(banner)"
          @click="onBannerClick(banner)"
        >
          <img
            v-if="imageUrl(banner)"
            :src="imageUrl(banner)"
            alt=""
            class="hero-backdrop"
            aria-hidden="true"
            :loading="i === 0 ? 'eager' : 'lazy'"
            @error="onImgError"
          />
          <img
            v-if="imageUrl(banner)"
            :src="imageUrl(banner)"
            :alt="title(banner)"
            class="hero-img"
            :loading="i === 0 ? 'eager' : 'lazy'"
            @error="onImgError"
          />
          <div v-else class="hero-fallback">
            <span>{{ title(banner) }}</span>
          </div>

          <div class="hero-shade" aria-hidden="true" />

          <div v-if="i === active" class="hero-caption">
            <span class="hero-badge">{{ t('home.announcement_badge') || '公告' }}</span>
            <h3 class="hero-title">{{ title(banner) }}</h3>
            <span class="hero-link">
              {{ t('announcements.go_link') }}
              <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
            </span>
          </div>
        </button>
      </div>

      <button
        v-if="canLoop"
        type="button"
        class="nav-btn prev"
        :aria-label="t('home.banner_prev')"
        @click.stop="prev"
      >
        <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M15.41 7.41 14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>
      </button>
      <button
        v-if="canLoop"
        type="button"
        class="nav-btn next"
        :aria-label="t('home.banner_next')"
        @click.stop="next"
      >
        <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M10 6 8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>
      </button>

      <div v-if="canLoop" class="hero-footer">
        <div class="hero-dots">
          <button
            v-for="(_, i) in banners"
            :key="i"
            type="button"
            class="dot"
            :class="{ active: i === active }"
            :aria-label="t('home.banner_slide', { n: i + 1 })"
            @click.stop="goTo(i)"
          />
        </div>
        <div class="hero-progress" aria-hidden="true">
          <div :key="active" class="hero-progress-fill" />
        </div>
      </div>
    </div>

    <div v-if="activeBanner && canLoop" class="hero-counter" aria-hidden="true">
      {{ String(active + 1).padStart(2, '0') }} / {{ String(slideCount).padStart(2, '0') }}
    </div>
  </section>
</template>

<style scoped>
.hero-carousel {
  position: relative;
  width: 100%;
}

.hero-frame {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: linear-gradient(135deg, #EEF4FA 0%, #FFFFFF 55%, #F5F7FA 100%);
  box-shadow: var(--shadow);
}

.hero-stage {
  position: relative;
  height: clamp(220px, 24vw, 300px);
}

.hero-slide {
  position: absolute;
  inset: 0;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
  opacity: 0;
  transform: scale(1.015);
  transition:
    opacity 0.65s ease,
    transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  overflow: hidden;
}

.hero-slide.is-active {
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
  z-index: 2;
}

.hero-backdrop {
  position: absolute;
  inset: -24px;
  width: calc(100% + 48px);
  height: calc(100% + 48px);
  object-fit: cover;
  filter: blur(22px) saturate(1.1);
  opacity: 0.42;
  transform: scale(1.06);
  pointer-events: none;
}

.hero-img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  display: block;
}

.hero-fallback {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, rgba(0, 61, 107, 0.08), rgba(0, 102, 204, 0.04));
  font-size: clamp(18px, 2.2vw, 26px);
  font-weight: 800;
  color: var(--primary);
  letter-spacing: 0.02em;
}

.hero-shade {
  position: absolute;
  inset: 0;
  z-index: 2;
  background:
    linear-gradient(180deg, rgba(0, 45, 82, 0.04) 0%, transparent 38%),
    linear-gradient(0deg, rgba(0, 36, 71, 0.72) 0%, rgba(0, 36, 71, 0.28) 42%, transparent 72%);
  pointer-events: none;
}

.hero-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  padding: 20px 24px 18px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  text-align: left;
  animation: caption-in 0.55s ease both;
}

@keyframes caption-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero-badge {
  display: inline-flex;
  align-items: center;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  border: 1px solid rgba(255, 255, 255, 0.28);
  color: rgba(255, 255, 255, 0.92);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  backdrop-filter: blur(6px);
}

.hero-title {
  margin: 0;
  max-width: min(72%, 560px);
  font-size: clamp(16px, 1.8vw, 22px);
  font-weight: 800;
  line-height: 1.35;
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.hero-link {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  margin-top: 2px;
  font-size: 13px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.88);
  transition: color 0.2s ease, transform 0.2s ease;
}

.hero-link svg {
  width: 16px;
  height: 16px;
}

.hero-slide:hover .hero-link {
  color: #fff;
  transform: translateX(2px);
}

.nav-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.65);
  background: rgba(255, 255, 255, 0.88);
  color: var(--primary);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
  box-shadow: 0 4px 14px rgba(0, 61, 107, 0.12);
  transition: background 0.2s, border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

.nav-btn svg {
  width: 20px;
  height: 20px;
}

.nav-btn:hover {
  background: #fff;
  border-color: #fff;
  transform: translateY(-50%) scale(1.05);
  box-shadow: 0 6px 18px rgba(0, 61, 107, 0.16);
}

.nav-btn.prev {
  left: 14px;
}

.nav-btn.next {
  right: 14px;
}

.hero-footer {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 8;
  pointer-events: none;
}

.hero-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  padding: 0 0 10px;
  pointer-events: auto;
}

.dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.45);
  border: none;
  padding: 0;
  cursor: pointer;
  transition: all 0.25s ease;
}

.dot.active {
  width: 20px;
  border-radius: 3px;
  background: #fff;
}

.dot:hover:not(.active) {
  background: rgba(255, 255, 255, 0.72);
}

.hero-progress {
  height: 3px;
  background: rgba(255, 255, 255, 0.18);
}

.hero-progress-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.55), #fff);
  animation: hero-progress 5.5s linear forwards;
}

@keyframes hero-progress {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

.hero-counter {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 10;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.82);
  border: 1px solid rgba(0, 61, 107, 0.1);
  color: var(--primary);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.06em;
  backdrop-filter: blur(8px);
  box-shadow: 0 2px 8px rgba(0, 61, 107, 0.08);
}

@media (prefers-reduced-motion: reduce) {
  .hero-slide,
  .hero-caption,
  .hero-progress-fill {
    animation: none;
    transition: none;
  }

  .hero-progress-fill {
    width: 100%;
  }
}
</style>
