<template>
  <div class="fullPage">
    <!-- 页面同步预加载：首屏关键图片加载完成前展示 loading -->
    <div
      v-if="isLoading"
      style="
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      "
    >
      <LoadingContent>{{ $t('loading') }}...</LoadingContent>
    </div>

    <!-- 活动主内容：保留旧页排名/奖励布局，资源和加载方式按新建页模式重构 -->
    <div v-else ref="bgRef" class="bg" @scroll.passive="checkRankingLoadTrigger">
      <!-- 顶部视觉区域：背景图内包含活动标题，按钮从旧页位置迁移 -->
      <itemCenter
        style="min-height: 151vw"
        :imgUrl="imageUrl('bg')"
        contentStyle="flex-direction: column; justify-content: flex-start; gap: 10vw;"
      >
        <div v-if="isInAppEnvironment" style="height: 30px"></div>

        <!-- 规则按钮 -->
        <div
          style="
            padding: 90vw 0 0;
            width: 100%;
            display: flex;
            justify-content: flex-end;
            align-items: center;
          "
        >
          <img
            v-smart-img.noFade
            :src="imageUrl('helpBt')"
            alt=""
            style="display: block; position: relative; width: 10vw; margin-right: 4vw"
            @click="maskLayerShow = true"
          />
        </div>
      </itemCenter>

      <!-- 倒计时：天/时/分/秒分别用 timeBg 承载 -->
      <section
        style="
          margin-top: -10vw;
          direction: ltr;
          display: flex;
          justify-content: center;
          align-items: center;
          gap: 1vw;
          padding: 0 4vw;
        "
      >
        <div style="width: 20vw; min-width: 0">
          <itemCenter
            style="min-height: 20vw"
            :imgUrl="imageUrl('timeBg')"
            contentStyle="padding: 1.6vw 1vw;"
          >
            <div class="timeText">{{ Days }}D</div>
          </itemCenter>
        </div>
        <div class="timeText" style="width: 2vw; flex: 0 0 2vw"></div>
        <div style="width: 20vw; min-width: 0">
          <itemCenter
            style="min-height: 20vw"
            :imgUrl="imageUrl('timeBg')"
            contentStyle="padding: 1.6vw 1vw;"
          >
            <div class="timeText">{{ Hours }}</div>
          </itemCenter>
        </div>
        <div class="timeText" style="width: 2vw; flex: 0 0 2vw">:</div>
        <div style="width: 20vw; min-width: 0">
          <itemCenter
            style="min-height: 20vw"
            :imgUrl="imageUrl('timeBg')"
            contentStyle="padding: 1.6vw 1vw;"
          >
            <div class="timeText">{{ Minutes }}</div>
          </itemCenter>
        </div>
        <div class="timeText" style="width: 2vw; flex: 0 0 2vw">:</div>
        <div style="width: 20vw; min-width: 0">
          <itemCenter
            style="min-height: 20vw"
            :imgUrl="imageUrl('timeBg')"
            contentStyle="padding: 1.6vw 1vw;"
          >
            <div class="timeText">{{ Seconds }}</div>
          </itemCenter>
        </div>
      </section>

      <!-- 排行榜/奖励切换按钮 -->
      <section
        style="
          display: flex;
          justify-content: space-around;
          align-items: center;
          gap: 2vw;
          margin-top: 4vw;
          padding: 0 2vw;
        "
      >
        <button
          type="button"
          style="flex: 1; min-width: 0; padding: 0; border: 0; background: transparent"
          @click="rankingShow = true"
        >
          <img
            v-smart-img.noFade
            :src="imageUrl(getImgName('rankingBt'))"
            alt=""
            style="display: block; width: 100%"
            :class="{ 'grayscale-container': !rankingShow }"
          />
        </button>

        <button
          type="button"
          style="flex: 1; min-width: 0; padding: 0; border: 0; background: transparent"
          @click="rankingShow = false"
        >
          <img
            v-smart-img.noFade
            :src="imageUrl(getImgName('rewardsBt'))"
            alt=""
            style="display: block; width: 100%"
            :class="{ 'grayscale-container': rankingShow }"
          />
        </button>
      </section>

      <!-- 排行榜内容 -->
      <section v-show="rankingShow" style="position: relative; width: 100%; margin: 10px 0 0">
        <div style="position: relative; z-index: 1">
          <!-- 前三名展示区 -->
          <itemCenter
            style="min-height: 99vw"
            :imgUrl="imageUrl(getImgName('RankingMain'))"
            contentStyle="padding: 22vw 5vw 0; flex-direction: column;"
          >
            <div style="width: 100%">
              <div style="display: flex; justify-content: center">
                <TopUser
                  ranking="1"
                  :BorderImgUrl="imageUrl('frameTop1')"
                  :avatarUrl="RankingHasTop3[0].avatar"
                  :name="RankingHasTop3[0].nickname"
                  :distributionValue="RankingHasTop3[0].quantity"
                  :valueIconUrl="coinIcon"
                  style="width: 55%"
                  @click="viewUserInfo(RankingHasTop3[0].userId)"
                />
              </div>

              <div
                style="
                  position: relative;
                  z-index: 3;
                  display: flex;
                  justify-content: space-between;
                  margin-top: -30%;
                  pointer-events: none;
                "
              >
                <div
                  style="width: 34%; pointer-events: auto"
                  @click.stop="viewUserInfo(RankingHasTop3[1].userId)"
                >
                  <TopUser
                    ranking="2"
                    :BorderImgUrl="imageUrl('frameTop2')"
                    :avatarUrl="RankingHasTop3[1].avatar"
                    :name="RankingHasTop3[1].nickname"
                    :distributionValue="RankingHasTop3[1].quantity"
                    :valueIconUrl="coinIcon"
                  />
                </div>

                <div
                  style="width: 34%; pointer-events: auto"
                  @click.stop="viewUserInfo(RankingHasTop3[2].userId)"
                >
                  <TopUser
                    ranking="3"
                    :BorderImgUrl="imageUrl('frameTop3')"
                    :avatarUrl="RankingHasTop3[2].avatar"
                    :name="RankingHasTop3[2].nickname"
                    :distributionValue="RankingHasTop3[2].quantity"
                    :valueIconUrl="coinIcon"
                  />
                </div>
              </div>
            </div>
          </itemCenter>

          <!-- 第四名及之后的排行榜列表 -->
          <div
            v-if="showRanking.length"
            style="position: relative; z-index: 2; width: 100vw; margin-bottom: 6vw"
          >
            <itemCenter
              v-for="(listItem, index) in showRanking"
              :key="`${listItem.userId || listItem.account || index}-${listItem.rank}`"
              style="min-height: 28vw"
              :imgUrl="imageUrl('RankingItem')"
              contentStyle="padding: 2vw 13vw 0;"
              :lazy="true"
              :immediate="index < 2"
              @click="viewUserInfo(listItem.userId)"
            >
              <div class="ranking-user">
                <div class="ranking-rank">{{ listItem.rank }}</div>
                <img
                  :src="listItem.avatar || ''"
                  alt=""
                  style="
                    display: block;
                    width: 3.5em;
                    margin: 0 2%;
                    aspect-ratio: 1 / 1;
                    border-radius: 50%;
                    object-fit: cover;
                  "
                  @error="handleAvatarImageError"
                />

                <div class="ranking-name-box">
                  <div class="ranking-name UserNickname">{{ listItem.nickname }}</div>
                  <div class="ranking-account UserNickname">
                    {{ $t('user_id_prefix') }} {{ listItem.account }}
                  </div>
                </div>
              </div>

              <div class="ranking-value">
                <img v-smart-img.noFade :src="coinIcon" alt="" class="coin-icon" />
                <div class="UserNickname">{{ listItem.quantity }}</div>
              </div>
            </itemCenter>
          </div>

          <div
            v-show="rankingShow && hasMoreRanking"
            ref="rankingLoadTrigger"
            style="width: 100%; height: 1px"
          ></div>

          <img
            v-smart-img.noFade
            :src="imageUrl('RankingBottomBorder')"
            alt=""
            style="display: block; width: 100%; margin-top: -40vw; position: relative; z-index: 1"
          />
        </div>
      </section>

      <!-- 奖励内容 -->
      <section
        v-show="!rankingShow"
        style="display: flex; flex-direction: column; align-items: center"
      >
        <div
          v-for="(rewardsTop, top) in rewardsList"
          :key="top"
          style="position: relative; width: 100%; margin: 10px 0"
        >
          <itemCenter
            style="min-height: 131vw"
            :imgUrl="topImg[Number(rewardsTop.rankRange) - 1] || topImg[top] || topImg[0]"
            contentStyle="display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 3.5vw; padding: 25vw 8vw 6vw;"
          >
            <div v-for="(reward, rewardIndex) in rewardsTop.rewards" :key="rewardIndex">
              <itemCenter
                :imgUrl="imageUrl('giftItemBg')"
                style="width: 100%; min-height: 41vw"
              >
                <img
                  :src="reward.cover || ''"
                  alt=""
                  style="display: block; width: 70%; object-fit: cover"
                  @error="(event) => handleRewardImageError(event, reward.type)"
                />
              </itemCenter>
              <div
                style="
                  width: 100%;
                  color: #ffe601;
                  font-size: 1.2em;
                  font-weight: 900;
                  font-style: italic;
                  text-align: center;
                "
              >
                {{ showDetail(reward.type, reward) }}
              </div>
            </div>
          </itemCenter>
        </div>
      </section>

      <!-- 底部固定我的排名占位 -->
      <div style="height: 30vw"></div>

      <!-- 底部固定我的排名 -->
      <itemCenter
        style="min-height: 28vw; position: fixed; bottom: 0; left: 0; z-index: 2"
        :imgUrl="imageUrl('myRankingBg')"
        contentStyle="padding: 2vw 8vw 0;"
      >
        <div class="ranking-user">
          <div class="ranking-rank">{{ myRanking.rank || 999 }}</div>
          <img
            :src="myRanking.avatar || ''"
            alt=""
            style="
              display: block;
              width: 4em;
              aspect-ratio: 1 / 1;
              border-radius: 50%;
              object-fit: cover;
            "
            @error="handleAvatarImageError"
          />

          <div class="ranking-name-box">
            <div class="ranking-name UserNickname">{{ myRanking.nickname }}</div>
          </div>
        </div>

        <div class="ranking-value">
          <img v-smart-img.noFade :src="coinIcon" alt="" class="coin-icon" />
          <div>{{ myRanking.quantity || 0 }}</div>
        </div>
      </itemCenter>

      <!-- 规则弹窗：使用 itemCenter 承载弹窗背景，内部通过多语言 key 展示说明文本 -->
      <maskLayer :maskLayerShow="maskLayerShow" @click="maskLayerShow = false">
        <div style="width: 100%; margin: 20% 0" @click.stop>
          <itemCenter
            style="min-height: 113vw"
            :imgUrl="imageUrl(getImgName('helpInfoBg'))"
            contentStyle="inset: 25vw 7vw 10vw; overflow-y: auto; display: block;"
          >
            <div class="helpInfo">
              <p v-for="ruleKey in helpRuleKeys" :key="ruleKey">{{ $t(ruleKey) }}</p>
            </div>
          </itemCenter>
        </div>
      </maskLayer>
    </div>
  </div>
</template>

<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
import { isInApp, viewUserInfo } from '@/utils/appBridge.js'
import { connectToApp } from '@/utils/appConnector.js'
import { useLangStore } from '@/stores/lang'
import { getPngUrl } from '@/config/imagePaths.js'
import { preloadImages, preloadImagesIdle } from '@/utils/image/imagePreloader.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import { useDebounce } from '@/utils/useDebounce.js'
import { getRankingListAndMyRanking, getThisWeekRewardsAndGifts } from '@/api/activity.js'
import itemCenter from '@/components/itemCenter.vue'
import maskLayer from '@/components/MaskLayer.vue'
import TopUser from './components/topUser.vue'
import { pageConfig } from './page.config.js'

const coinIcon = new URL('/src/assets/icon/Aslan/coin.png', import.meta.url).href

const langStore = useLangStore()
const currentLangType = computed(() => langStore.selectedLang?.type || 'en')
const localizedImageMap = pageConfig.images?.localized || {}

const isInAppEnvironment = ref(false)
const maskLayerShow = ref(false)
const isLoading = ref(true)
const rankingShow = ref(true)

const Days = ref(0)
const Hours = ref('00')
const Minutes = ref('00')
const Seconds = ref('00')
let timer = null

const Ranking = ref([])
const rankingAllData = ref([])
const myRanking = ref({})
const rewardsList = ref([])
const bgRef = ref(null)
const rankingLoadTrigger = ref(null)
const rankingPageSize =
  pageConfig.modules.sections.find((item) => item.name === 'ranking')?.pageSize || 10
let rankingObserver = null

const imageUrl = (filename) => getPngUrl(pageConfig.assetPath, filename)

const getImgName = (filename) => {
  const lang = currentLangType.value
  const localizedNames = localizedImageMap[lang] || []

  if (lang === 'en' || !localizedNames.includes(filename)) {
    return filename
  }

  return `${filename}_${lang}`
}

const topImg = computed(() => [
  imageUrl('rewardBgTop1'),
  imageUrl('rewardBgTop2'),
  imageUrl('rewardBgTop3'),
])

const helpRuleKeys = [
  'greedy_king_help_rule_1',
  'greedy_king_help_rule_2',
  'greedy_king_help_rule_3',
  'greedy_king_help_rule_4',
  'greedy_king_help_rule_5',
]

const normalizeRankingUser = (user = {}, index = null) => {
  return {
    ...user,
    userId: user.userId || user.uid || user.id || '',
    avatar: user.avatar || user.userAvatar || '',
    nickname: user.nickname || user.userName || user.userNickname || '',
    quantity: user.quantity ?? user.amount ?? user.total ?? 0,
    rank: user.rank ?? user.ranking ?? (index === null ? '' : index + 1),
    account: user.account || user.specialAccount || '',
  }
}

const RankingHasTop3 = computed(() => {
  const ranking = [...Ranking.value]

  if (ranking.length < 3) {
    ranking.push(
      ...Array.from({ length: 3 - ranking.length }, (_, index) => ({
        userId: '',
        avatar: '',
        nickname: '',
        quantity: '',
        rank: ranking.length + index + 1,
        account: '',
      })),
    )
  }

  return ranking
})

const showRanking = computed(() => Ranking.value.filter((_, index) => index >= 3))

const hasMoreRanking = computed(() => Ranking.value.length < rankingAllData.value.length)

const appendRankingBatch = () => {
  if (!hasMoreRanking.value) return

  const start = Ranking.value.length
  Ranking.value.push(...rankingAllData.value.slice(start, start + rankingPageSize))
}

const isRankingTriggerVisible = () => {
  if (!rankingLoadTrigger.value) return false

  const triggerRect = rankingLoadTrigger.value.getBoundingClientRect()
  const rootRect = bgRef.value?.getBoundingClientRect()
  const viewportTop = rootRect?.top ?? 0
  const viewportBottom = rootRect?.bottom ?? window.innerHeight

  return triggerRect.top <= viewportBottom && triggerRect.bottom >= viewportTop
}

const handleRankingLoadTrigger = () => {
  if (!rankingShow.value || !hasMoreRanking.value || !isRankingTriggerVisible()) return

  appendRankingBatch()
  nextTick(() => {
    if (hasMoreRanking.value && isRankingTriggerVisible()) {
      debouncedLoadMoreRanking()
    }
  })
}

const debouncedLoadMoreRanking = useDebounce(handleRankingLoadTrigger, 300)

const checkRankingLoadTrigger = () => {
  if (!rankingShow.value || !hasMoreRanking.value) return
  debouncedLoadMoreRanking()
}

const destroyRankingObserver = () => {
  if (rankingObserver) {
    rankingObserver.disconnect()
    rankingObserver = null
  }
}

const initRankingObserver = async () => {
  destroyRankingObserver()
  await nextTick()

  if (!rankingLoadTrigger.value || typeof IntersectionObserver === 'undefined') return

  rankingObserver = new IntersectionObserver(
    (entries) => {
      if (entries.some((entry) => entry.isIntersecting)) {
        debouncedLoadMoreRanking()
      }
    },
    {
      root: bgRef.value || null,
      rootMargin: '0px 0px 150px 0px',
      threshold: 0.1,
    },
  )

  rankingObserver.observe(rankingLoadTrigger.value)
  checkRankingLoadTrigger()
}

const loadInitialRanking = () => {
  appendRankingBatch()
  nextTick(() => checkRankingLoadTrigger())
}

// 获取北京时间 2026 年 6 月 8 日早上 5 点的时间戳，写法对齐 BountyFootball。
const getTargetTime = () => {
  const targetDate = new Date(2026, 5, 8, 5, 0, 0)
  return targetDate.getTime()
}

const targetTime = ref(getTargetTime())

const formatTime = (value) => {
  return value < 10 ? `0${value}` : value
}

const getCountdown = () => {
  const now = Date.now()
  let diff = targetTime.value - now

  if (diff <= 0) {
    Days.value = 0
    Hours.value = '00'
    Minutes.value = '00'
    Seconds.value = '00'

    if (timer) {
      clearInterval(timer)
      timer = null
    }
    return
  }

  const totalSeconds = Math.floor(diff / 1000)
  Days.value = Math.floor(totalSeconds / 86400)
  Hours.value = formatTime(Math.floor((totalSeconds % 86400) / 3600))
  Minutes.value = formatTime(Math.floor((totalSeconds % 3600) / 60))
  Seconds.value = formatTime(totalSeconds % 60)
}

const showDetail = (type, reward) => formatRewardDisplay(type, reward)

const getListAndMy = async () => {
  const params = {
    activityType: pageConfig.activity.activityType,
    cycleKey: pageConfig.activity.cycleKey,
  }

  if (pageConfig.activity.cycleType) {
    params.cycleType = pageConfig.activity.cycleType
  }

  const resRanking = await getRankingListAndMyRanking(params)

  if (resRanking.status && resRanking.body) {
    myRanking.value = normalizeRankingUser(resRanking.body.currentUserRank || {}, null)
    rankingAllData.value = (resRanking.body.rankingList || []).map((item, index) =>
      normalizeRankingUser(item, index),
    )
    Ranking.value = []
    loadInitialRanking()
    await initRankingObserver()
    return
  }

  myRanking.value = {}
  Ranking.value = []
  rankingAllData.value = []
  destroyRankingObserver()
}

const appendLegacyDollarRewards = (list = []) => {
  const dollarRewards = [50, 30, 10]

  return list.map((item, index) => {
    const rewards = Array.isArray(item.rewards) ? [...item.rewards] : []

    if (dollarRewards[index]) {
      rewards.push({
        type: 'DOLLARS',
        content: dollarRewards[index],
      })
    }

    return {
      ...item,
      rewards,
    }
  })
}

const getRewardsAndGifts = async () => {
  if (!pageConfig.activity.templateId) return

  const resRewards = await getThisWeekRewardsAndGifts(pageConfig.activity.templateId)
  if (resRewards.status && resRewards.body) {
    rewardsList.value = appendLegacyDollarRewards(resRewards.body.butOneRewards || [])
  }
}

const initData = async () => {
  await Promise.all([getListAndMy(), getRewardsAndGifts()])
}

const resolvePreloadUrls = (items = []) => {
  return items.map((item) => {
    if (typeof item === 'string') {
      return imageUrl(getImgName(item))
    }

    return imageUrl(item.localized ? getImgName(item.name) : item.name)
  })
}

const completePreloading = async () => {
  try {
    await Promise.all([initData(), preloadImages(resolvePreloadUrls(pageConfig.preload.blocking))])
  } catch (error) {
    console.error('预加载过程中发生错误:', error)
  } finally {
    isLoading.value = false
    preloadImagesIdle(resolvePreloadUrls(pageConfig.preload.background))
  }
}

const connectToAppHandler = async () => {
  await connectToApp(() => {
    completePreloading()
  })
}

onMounted(() => {
  connectToAppHandler()
  isInAppEnvironment.value = isInApp()

  getCountdown()
  timer = setInterval(getCountdown, 1000)
})

onUnmounted(() => {
  if (timer) {
    clearInterval(timer)
  }

  destroyRankingObserver()
  debouncedLoadMoreRanking.cancel()
})
</script>

<style lang="scss" scoped>
* {
  color: #fff;
}

.fullPage {
  width: 100%;
  height: 100vh;
  overflow: hidden;
  background: #2a1046;
}

.bg {
  width: 100vw;
  height: 100vh;
  overflow-x: hidden;
  overflow-y: auto;
  position: relative;
  background-color: #2a1046;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.bg::-webkit-scrollbar {
  display: none;
}

.bg :deep(.mask-layer) {
  position: fixed;
  inset: 0;
  z-index: 10000 !important;
}

.timeText {
  width: 100%;
  color: #fff;
  font-size: 2em;
  font-weight: 600;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
}

.grayscale-container {
  filter: grayscale(100%) brightness(90%);
}

.ranking-user {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: space-around;
  align-items: center;
  gap: 4px;
}

.ranking-rank {
  min-width: 2em;
  color: #ffe601;
  font-weight: 700;
  text-align: center;
}

.ranking-name-box {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.ranking-name {
  color: #fff;
  font-weight: 860;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.ranking-account {
  color: #fff;
  font-weight: 590;
}

.ranking-value {
  width: auto;
  min-width: 0;
  display: flex;
  align-items: center;
  color: #ffe601;
  font-weight: 700;
}

.coin-icon {
  display: block;
  width: 1.5em;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.helpInfo {
  display: flex;
  flex-direction: column;
  gap: 1vw;
  padding: 0 1vw;
}

.helpInfo > p {
  color: #fff;
  font-size: 1em;
  font-weight: 400;
  line-height: 1.4;
  margin: 0;
}

.UserNickname {
  font-size: 0.8em;
}

@media screen and (max-width: 360px) {
  * {
    font-size: 10px;
  }
}

@media screen and (min-width: 360px) {
  * {
    font-size: 14px;
  }
}

@media screen and (min-width: 768px) {
  * {
    font-size: 24px;
  }
}

@media screen and (min-width: 1024px) {
  * {
    font-size: 32px;
  }
}
</style>
