<template>
  <!-- 页面根容器：承载加载态和活动正式内容 -->
  <div
    class="full-page"
    style="
      position: relative;
      width: 100vw;
      height: 100vh;
      overflow: hidden;
      background: #101e14;
      scrollbar-width: none;
    "
  >
    <!-- 首屏加载动画：关键图片、排行榜和赛事数据加载完成后再展示页面 -->
    <div
      v-if="isLoading"
      style="
        position: relative;
        z-index: 1;
        width: 100vw;
        height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
      "
    >
      <LoadingContent>{{ $t('loading') }}...</LoadingContent>
    </div>

    <!-- 页面模块列表：按头图、排行榜、赛事列表从上往下排列 -->
    <main
      v-else
      style="
        position: relative;
        z-index: 1;
        display: flex;
        flex-direction: column;
        gap: 2vw;
        width: 100vw;
        height: 100vh;
        overflow-x: hidden;
        overflow-y: auto;
      "
    >
      <!-- 最底层背景图：bg2 拉伸铺满当前视口 -->
      <img
        v-smart-img.noFade
        :src="pngUrl('bg2')"
        alt=""
        style="
          position: fixed;
          inset: 0;
          z-index: 0;
          display: block;
          width: 100vw;
          height: 100vh;
          object-fit: fill;
          pointer-events: none;
        "
      />

      <!-- 头部模块：使用 bg 大图承载，内部放置右侧规则按钮 -->
      <itemCenter
        style="width: 100vw; min-height: 151vw; max-height: 152vw"
        :imgUrl="pngUrl('bg')"
        contentStyle="padding: 87vw 0 0; align-items: flex-start; justify-content: flex-start; box-sizing: border-box;"
      >
        <!-- 规则按钮行：点击 ruleBt 打开规则弹窗 -->
        <div style="width: 100%; display: flex; justify-content: flex-end">
          <img
            v-smart-img.noFade
            :src="pngUrl('ruleBt')"
            alt=""
            style="width: 13.6vw; display: block"
            @click.stop="handleOpenRulePopup"
          />
        </div>
      </itemCenter>

      <!-- 排行榜模块：主背景、前三名、列表项和底边框统一放在这里 -->
      <section>
        <div style="position: relative; width: 100vw">
          <!-- 排行榜底色背景：配合 RankingMain、RankingItem 和底边框形成完整排行榜容器 -->
          <div
            style="position: absolute; inset: 15vw 2vw 4vw; z-index: 0; background-color: #0d4805"
          ></div>

          <!-- 排行榜主图区：RankingMain 内展示前三名头像框 -->
          <itemCenter
            style="width: 100vw; min-height: 92vw; max-height: 93vw"
            :imgUrl="pngUrl('RankingMain')"
            contentStyle="direction: ltr; padding: 0; flex-direction: column; align-items: center; justify-content: space-between; box-sizing: border-box;"
          >
            <!-- 排行榜礼物按钮：右上角绝对定位，点击后展示奖励弹窗 -->
            <img
              v-smart-img.noFade
              :src="pngUrl('giftBt')"
              alt=""
              style="
                position: absolute;
                top: 18vw;
                right: 6vw;
                z-index: 3;
                width: 10vw;
                display: block;
              "
              @click.stop="handleOpenRewardPopup"
            />

            <!-- 前三名模块：沿用 RankingMain 内容区样式，包裹前三名领奖台 -->
            <div
              style="
                width: 100%;
                padding: 20vw 6vw 0;
                display: flex;
                align-items: flex-start;
                justify-content: center;
                box-sizing: border-box;
              "
            >
              <!-- 前三名容器：同一行展示，通过 flex order 固定为第二名、第一名、第三名 -->
              <div
                style="
                  width: 100%;
                  height: 45vw;
                  display: flex;
                  align-items: flex-end;
                  justify-content: space-between;
                  gap: 1vw;
                "
              >
                <TopUser
                  style="width: 26vw; order: 2"
                  ranking="1"
                  :frameUrl="pngUrl('frameTop1')"
                  :avatarUrl="topUsers[0].avatarUrl"
                  :name="topUsers[0].name"
                  :userId="topUsers[0].account"
                  :vipUrl="getVipLevelUrl(topUsers[0].vipLevelName)"
                  :charmLevelUrl="pngUrl(getLevelBgImageName('userLevel', topUsers[0].charmLevel))"
                  :wealthLevelUrl="
                    pngUrl(getLevelBgImageName('wealthLevel', topUsers[0].wealthLevel))
                  "
                  :charmLevel="topUsers[0].charmLevel"
                  :wealthLevel="topUsers[0].wealthLevel"
                  @click="handleRankingClick(topUsers[0])"
                />

                <TopUser
                  style="width: 24vw; order: 1"
                  ranking="2"
                  :frameUrl="pngUrl('frameTop2')"
                  :avatarUrl="topUsers[1].avatarUrl"
                  :name="topUsers[1].name"
                  :userId="topUsers[1].account"
                  :vipUrl="getVipLevelUrl(topUsers[1].vipLevelName)"
                  :charmLevelUrl="pngUrl(getLevelBgImageName('userLevel', topUsers[1].charmLevel))"
                  :wealthLevelUrl="
                    pngUrl(getLevelBgImageName('wealthLevel', topUsers[1].wealthLevel))
                  "
                  :charmLevel="topUsers[1].charmLevel"
                  :wealthLevel="topUsers[1].wealthLevel"
                  @click="handleRankingClick(topUsers[1])"
                />

                <TopUser
                  style="width: 24vw; order: 3"
                  ranking="3"
                  :frameUrl="pngUrl('frameTop3')"
                  :avatarUrl="topUsers[2].avatarUrl"
                  :name="topUsers[2].name"
                  :userId="topUsers[2].account"
                  :vipUrl="getVipLevelUrl(topUsers[2].vipLevelName)"
                  :charmLevelUrl="pngUrl(getLevelBgImageName('userLevel', topUsers[2].charmLevel))"
                  :wealthLevelUrl="
                    pngUrl(getLevelBgImageName('wealthLevel', topUsers[2].wealthLevel))
                  "
                  :charmLevel="topUsers[2].charmLevel"
                  :wealthLevel="topUsers[2].wealthLevel"
                  @click="handleRankingClick(topUsers[2])"
                />
              </div>
            </div>

            <!-- 展示更多模块：点击后展开第四名以后的排行榜列表 -->
            <div
              v-if="showMoreRankingEntry"
              style="
                width: 100%;
                position: relative;
                z-index: 2;
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 2vw;
              "
              @click="handleShowRankingList"
            >
              <span style="color: #fff; font-size: 1.2em; font-weight: 600">Show All Users</span>
              <img
                v-smart-img.noFade
                :src="pngUrl('showMoreBt')"
                alt=""
                style="width: 2em; display: block"
              />
            </div>
          </itemCenter>

          <!-- 展开后的排行榜列表：点击 Show All Users 后才展示 RankingItem 模块 -->
          <template v-if="showExpandedRankingList">
            <!-- 第四名以后排行榜列表：使用 RankingItem 逐条承载接口数据 -->
            <itemCenter
              v-for="(rankingItem, index) in rankingListAfterTop3"
              :key="rankingItem.userId || index"
              style="width: 100vw; min-height: 23vw; max-height: 24vw; margin-top: -2vw"
              :imgUrl="pngUrl('RankingItem')"
              contentStyle="padding: 3vw 8vw 0; box-sizing: border-box; justify-content: space-between;"
              @click="handleRankingClick(rankingItem)"
            >
              <!-- 列表项用户信息区：排名、头像、昵称、id 和等级行 -->
              <div style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 2vw">
                <div
                  style="
                    color: #fff;
                    font-size: 1em;
                    font-weight: 800;
                    line-height: 1;
                    white-space: nowrap;
                  "
                >
                  {{ rankingItem.rank }}
                </div>
                <img
                  :src="rankingItem.avatarUrl || ''"
                  alt=""
                  style="
                    width: 3.5em;
                    aspect-ratio: 1 / 1;
                    display: block;
                    flex: 0 0 3.5em;
                    border-radius: 50%;
                    object-fit: cover;
                  "
                  @error="handleAvatarImageError"
                />
                <!-- 名称信息区：昵称、id、等级分三行展示 -->
                <div
                  class="ranking-name-box"
                  style="flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.4vw"
                >
                  <div class="ranking-name">{{ rankingItem.name }}</div>
                  <div class="ranking-id">{{ $t('user_id_prefix') }} {{ rankingItem.account }}</div>
                  <!-- 等级行：VIP、魅力等级、财富等级和前三名同一套展示规则 -->
                  <div style="display: flex; align-items: center; gap: 1vw">
                    <img
                      v-if="getVipLevelUrl(rankingItem.vipLevelName)"
                      v-smart-img.noFade
                      :src="getVipLevelUrl(rankingItem.vipLevelName)"
                      alt=""
                      style="width: 12vw; display: block"
                    />
                    <itemCenter
                      :imgUrl="pngUrl(getLevelBgImageName('userLevel', rankingItem.charmLevel))"
                      style="width: 12vw; min-height: 7vw; max-height: 8vw"
                      contentStyle="direction: ltr;padding: 0 0 0 42%; align-items: center; justify-content: center; box-sizing: border-box;"
                    >
                      <span style="color: #fff; font-size: 1em; font-weight: 700; line-height: 1">
                        {{ rankingItem.charmLevel || 0 }}
                      </span>
                    </itemCenter>
                    <itemCenter
                      :imgUrl="pngUrl(getLevelBgImageName('wealthLevel', rankingItem.wealthLevel))"
                      style="width: 12vw; min-height: 6vw; max-height: 7vw"
                      contentStyle="direction: ltr;padding: 0 0 0 36%; align-items: center; justify-content: center; box-sizing: border-box;"
                    >
                      <span style="color: #fff; font-size: 1em; font-weight: 700; line-height: 1">
                        {{ rankingItem.wealthLevel || 0 }}
                      </span>
                    </itemCenter>
                  </div>
                </div>
              </div>
              <!-- 列表项贡献值：接口 quantity 字段归一化后的展示值 -->
              <div
                style="
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  gap: 0.8vw;
                  color: #fff;
                  font-size: 1em;
                  font-weight: 800;
                  line-height: 1;
                  white-space: nowrap;
                "
              >
                <img
                  v-smart-img
                  src="/src/assets/icon/Aslan/coin.png"
                  alt=""
                  style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
                />
                {{ rankingItem.amount }}
              </div>
            </itemCenter>
          </template>

          <!-- 排行榜底边框：用于收尾主背景和列表区域 -->
          <img
            v-smart-img.noFade
            :src="pngUrl('RankingBottomBorder')"
            alt=""
            style="
              position: relative;
              z-index: 1;
              display: block;
              width: 100vw;
              margin-top: -12vw;
              pointer-events: none;
            "
          />
        </div>

        <!-- 收起列表模块：展示在整个排行榜底边框下方，点击后隐藏列表 -->
        <div
          v-if="showExpandedRankingList"
          style="
            position: relative;
            z-index: 2;
            width: 100vw;
            padding: 2vw 0 4vw;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 2vw;
          "
          @click="handleCollapseRankingList"
        >
          <span style="color: #fff; font-size: 1.2em; font-weight: 600">Collapse List</span>
          <img
            v-smart-img.noFade
            :src="pngUrl('showMoreBt')"
            alt=""
            style="width: 2em; display: block; transform: scaleY(-1)"
          />
        </div>
      </section>

      <!-- 赛事列表模块：排行榜下方第二个业务模块，展示可竞猜和已结束比赛列表 -->
      <section style="width: 100vw">
        <!-- 赛事列表背景容器：使用 EventlistBg 承载切换按钮和比赛列表 -->
        <itemCenter
          style="width: 100vw; min-height: 244vw; max-height: 245vw"
          :imgUrl="pngUrl('EventlistBg')"
          contentStyle="display: flex; flex-direction: column; justify-content: flex-start; align-items: center; gap: 2vw; padding: 18vw 8vw 12vw; box-sizing: border-box;"
        >
          <!-- 赛事列表切换按钮模块：左右各占 50%，控制 Predict Now 和 Ended 列表 -->
          <div
            style="
              width: 100%;
              display: flex;
              align-items: center;
              justify-content: center;
              border-radius: 7.549px;
              border: 0.944px solid #5d6948;
              background: linear-gradient(180deg, #0b2415 0%, #051c12 100%);
              backdrop-filter: blur(13.449894905090332px);
              overflow: hidden;
            "
          >
            <!-- Predict Now 切换按钮：tab=0，展示可投注和比赛中赛事 -->
            <div :style="getMatchTabButtonStyle(0)" @click="handleMatchTabClick(0)">
              <span :style="getMatchTabTextStyle(0)">Predict Now!</span>
            </div>

            <!-- Ended 切换按钮：tab=1，当前只切换接口，列表内容后续补充 -->
            <div :style="getMatchTabButtonStyle(1)" @click="handleMatchTabClick(1)">
              <span :style="getMatchTabTextStyle(1)">Ended</span>
            </div>
          </div>

          <!-- 赛事列表滚动模块：列表内部滚动并隐藏滚动条，当前每次请求固定 size=10 -->
          <div
            style="
              width: 100%;
              flex: 1;
              min-height: 0;
              display: flex;
              flex-direction: column;
              gap: 2vw;
              overflow-x: hidden;
              overflow-y: auto;
              box-sizing: border-box;
              scrollbar-width: none;
            "
          >
            <!-- 赛事列表项：Predict Now 和 Ended 使用独立数据源，避免切换时列表数据串用 -->
            <!-- Predict Now 列表容器：使用 v-show 保留 DOM，减少固定图片在 tab 切换时反复加载 -->
            <div
              v-show="activeMatchTab === 0"
              style="width: 100%; display: flex; flex-direction: column; gap: 2vw"
            >
              <template v-for="matchItem in predictMatchList" :key="matchItem.matchId">
                <!-- Predict Now 新列表项：上方为原赛事卡片，下方为总奖池入口 -->
                <div
                  style="
                    width: 100%;
                    flex: 0 0 auto;
                    display: flex;
                    flex-direction: column;
                    gap: 2vw;
                  "
                >
                  <itemCenter
                    style="width: 100%; min-height: 52vw; max-height: 53vw"
                    :imgUrl="pngUrl('matchBg')"
                    contentStyle="width: 100%; height: 100%; padding: 0; box-sizing: border-box; display: flex; flex-direction: column; justify-content: space-between; align-items: center;"
                  >
                    <!-- 赛事状态行：左侧展示参与状态或开赛时间，右侧展示参与人数 -->
                    <div
                      style="
                        width: 100%;
                        display: flex;
                        align-items: flex-start;
                        justify-content: space-between;
                        gap: 2vw;
                        box-sizing: border-box;
                      "
                    >
                      <!-- 左上角状态标签：比赛中已参与、比赛中未参与、未开赛三种展示规则 -->
                      <div :style="getPredictMatchBadgeStyle(matchItem)">
                        <span
                          v-if="getPredictMatchBadgeType(matchItem) === 'joined'"
                          style="
                            display: block;
                            width: 1.4vw;
                            aspect-ratio: 1 / 1;
                            border-radius: 50%;
                            background: #14ff00;
                            flex: 0 0 auto;
                          "
                        ></span>
                        <span>{{ getPredictMatchBadgeText(matchItem) }}</span>
                      </div>

                      <!-- 右上角参与人数：numPeople 图标加 joinCount 字段 -->
                      <div
                        style="
                          display: flex;
                          align-items: center;
                          justify-content: flex-end;
                          gap: 1vw;
                          padding: 1vw 2vw 0 0;
                          color: #fff;
                          line-height: 1;
                          white-space: nowrap;
                        "
                      >
                        <img
                          v-smart-img.noFade
                          :src="pngUrl('numPeople')"
                          alt=""
                          style="
                            display: block;
                            width: 5vw;
                            aspect-ratio: 1 / 1;
                            object-fit: contain;
                          "
                        />
                        <span style="font-size: 1em; font-weight: 500">{{
                          matchItem.joinCount || 0
                        }}</span>
                      </div>
                    </div>

                    <!-- 赛事简要信息：主国、平局、客国三列展示旗帜、文案和投注占比 -->
                    <div
                      style="
                        width: 100%;
                        display: flex;
                        align-items: flex-start;
                        justify-content: center;
                        gap: 4vw;
                        box-sizing: border-box;
                        padding: 0 4.5vw 2vw;
                      "
                    >
                      <!-- 主国信息项：展示 homeFlag、homeTeam、homePercent -->
                      <div
                        style="
                          flex: 1;
                          min-width: 0;
                          display: flex;
                          flex-direction: column;
                          align-items: center;
                          justify-content: flex-start;
                          gap: 1vw;
                        "
                      >
                        <div
                          style="
                            width: 100%;
                            aspect-ratio: 1 / 1;
                            display: flex;
                            align-items: center;
                            justify-content: center;
                          "
                        >
                          <img
                            :src="matchItem.homeFlag"
                            alt=""
                            style="
                              display: block;
                              width: 80%;
                              aspect-ratio: 1 / 1;
                              object-fit: contain;
                            "
                          />
                        </div>
                        <div
                          style="
                            max-width: 100%;
                            overflow: hidden;
                            color: #fff;
                            font-size: 1em;
                            font-weight: 500;
                            line-height: 1.2;
                            text-align: center;
                            text-overflow: ellipsis;
                            white-space: nowrap;
                          "
                        >
                          {{ matchItem.homeTeam }}
                        </div>
                        <div
                          style="color: #71ce6e; font-size: 1em; font-weight: 500; line-height: 1"
                        >
                          {{ formatMatchPercent(matchItem.homePercent) }}
                        </div>
                      </div>

                      <!-- 平局信息项：中间列不展示图片，只展示 DRAW 和 drawPercent -->
                      <div
                        style="
                          flex: 1;
                          min-width: 0;
                          display: flex;
                          flex-direction: column;
                          align-items: center;
                          justify-content: flex-start;
                          gap: 1vw;
                        "
                      >
                        <div style="width: 100%; aspect-ratio: 1 / 1"></div>
                        <div
                          style="color: #fff; font-size: 1em; font-weight: 500; line-height: 1.2"
                        >
                          DRAW
                        </div>
                        <div
                          style="color: #a0a181; font-size: 1em; font-weight: 500; line-height: 1"
                        >
                          {{ formatMatchPercent(matchItem.drawPercent) }}
                        </div>
                      </div>

                      <!-- 客国信息项：展示 awayFlag、awayTeam、awayPercent -->
                      <div
                        style="
                          flex: 1;
                          min-width: 0;
                          display: flex;
                          flex-direction: column;
                          align-items: center;
                          justify-content: flex-start;
                          gap: 1vw;
                        "
                      >
                        <div
                          style="
                            width: 100%;
                            aspect-ratio: 1 / 1;
                            display: flex;
                            align-items: center;
                            justify-content: center;
                          "
                        >
                          <img
                            :src="matchItem.awayFlag"
                            alt=""
                            style="
                              display: block;
                              width: 80%;
                              aspect-ratio: 1 / 1;
                              object-fit: contain;
                            "
                          />
                        </div>
                        <div
                          style="
                            max-width: 100%;
                            overflow: hidden;
                            color: #fff;
                            font-size: 1em;
                            font-weight: 500;
                            line-height: 1.2;
                            text-align: center;
                            text-overflow: ellipsis;
                            white-space: nowrap;
                          "
                        >
                          {{ matchItem.awayTeam }}
                        </div>
                        <div
                          style="color: #71ce6e; font-size: 1em; font-weight: 500; line-height: 1"
                        >
                          {{ formatMatchPercent(matchItem.awayPercent) }}
                        </div>
                      </div>
                    </div>
                  </itemCenter>
                  <!-- 总奖池入口：点击进入赛事详情页，后续详情页负责押注和押注状态展示 -->
                  <div :style="totalPrizePoolStyle" @click="handleOpenEventDetail(matchItem)">
                    <div style="display: flex; align-items: center; gap: 1vw; min-width: 0">
                      <span
                        style="color: #fff; font-size: 1em; font-weight: 600; white-space: nowrap"
                      >
                        TOTAL PRIZE POOL
                      </span>
                      <img
                        v-smart-img
                        src="/src/assets/icon/Aslan/coin.png"
                        alt=""
                        style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
                      />
                      <span style="color: #ffe083; font-size: 1em; font-weight: 700">
                        {{ matchItem.totalPoolFormat || matchItem.totalPool || 0 }}
                      </span>
                    </div>
                    <img
                      v-smart-img.noFade
                      :src="pngUrl('rightBt')"
                      alt=""
                      style="display: block; width: 2em; flex: 0 0 auto"
                    />
                  </div>
                </div>
              </template>
            </div>

            <!-- Ended 列表项：使用独立卡片样式展示已结束赛事，不使用 matchBg 背景组件 -->
            <!-- Ended 列表容器：使用 v-show 保留 DOM，避免 numPeople、rightBt、drawSign 等固定图片重复加载 -->
            <div
              v-show="activeMatchTab === 1"
              style="width: 100%; display: flex; flex-direction: column; gap: 2vw"
            >
              <template v-for="matchItem in endedMatchList" :key="matchItem.matchId">
                <!-- Ended 新列表项：上方为已结束赛事卡片，下方为总奖池入口 -->
                <div
                  style="
                    width: 100%;
                    flex: 0 0 auto;
                    display: flex;
                    flex-direction: column;
                    gap: 2vw;
                  "
                >
                  <div :style="endedMatchItemStyle">
                    <!-- Ended 状态行：左侧展示中奖/未中奖/未参与状态，右侧展示参与人数 -->
                    <div
                      style="
                        width: 100%;
                        display: flex;
                        align-items: flex-start;
                        justify-content: space-between;
                        gap: 2vw;
                        box-sizing: border-box;
                      "
                    >
                      <!-- Ended 左侧状态标签：参与且中奖、参与未中奖、未参与三种视觉状态 -->
                      <div :style="getEndedMatchBadgeStyle(matchItem)">
                        <template v-if="getEndedMatchStatusType(matchItem) === 'win'">
                          <span>+</span>
                          <img
                            v-smart-img
                            src="/src/assets/icon/Aslan/coin.png"
                            alt=""
                            style="
                              display: block;
                              width: 1.5em;
                              aspect-ratio: 1/1;
                              object-fit: cover;
                            "
                          />
                          <span>{{ getEndedMatchWinAmount(matchItem) }}</span>
                        </template>
                        <span v-else>{{ getEndedMatchBadgeText(matchItem) }}</span>
                      </div>

                      <!-- Ended 右上角参与人数：和 Predict Now 保持同一套 numPeople 展示规则 -->
                      <div
                        style="
                          display: flex;
                          align-items: center;
                          justify-content: flex-end;
                          gap: 1vw;
                          padding: 1vw 2vw 0 0;
                          color: #fff;
                          font-size: 1em;
                          font-weight: 500;
                          line-height: 1;
                          white-space: nowrap;
                        "
                      >
                        <img
                          v-smart-img.noFade
                          :src="pngUrl('numPeople')"
                          alt=""
                          style="
                            display: block;
                            width: 4vw;
                            aspect-ratio: 1 / 1;
                            object-fit: contain;
                          "
                        />
                        <span>{{ matchItem.joinCount || 0 }}</span>
                      </div>
                    </div>

                    <!-- Ended 押注选项行：主方、平局、客方三列均分展示，只展示不绑定押注点击 -->
                    <div
                      style="
                        width: 100%;
                        display: flex;
                        align-items: stretch;
                        justify-content: center;
                        gap: 2vw;
                        box-sizing: border-box;
                        padding: 0 3vw 3vw;
                      "
                    >
                      <!-- Ended 单个押注选项：上半部分为赛事信息，下半部分为奖池和用户押注金额 -->
                      <div
                        v-for="betOption in getEndedBetOptions(matchItem)"
                        :key="betOption.option"
                        :style="getEndedBetOptionStyle(matchItem, betOption.option)"
                      >
                        <!-- 押注选项赛事信息：旗帜、国家名和占比 -->
                        <div
                          style="
                            width: 100%;
                            display: flex;
                            flex-direction: column;
                            align-items: center;
                            justify-content: flex-start;
                            gap: 1vw;
                          "
                        >
                          <div
                            style="
                              width: 100%;
                              aspect-ratio: 1 / 1.1;
                              display: flex;
                              align-items: center;
                              justify-content: center;
                              position: relative;
                            "
                          >
                            <img
                              v-if="betOption.isOssImage"
                              v-smart-img.noFade
                              :src="betOption.flagUrl"
                              alt=""
                              style="
                                display: block;
                                width: 68%;
                                aspect-ratio: 1 / 1;
                                object-fit: contain;
                              "
                            />
                            <img
                              v-else
                              :src="betOption.flagUrl"
                              alt=""
                              style="
                                display: block;
                                width: 70%;
                                aspect-ratio: 1 / 1;
                                object-fit: contain;
                              "
                            />
                            <!-- 胜方标识框：根据 result 字段叠加在主胜、平局或客胜对应图片上方 -->
                            <img
                              v-if="isEndedBetOptionWinner(matchItem, betOption.option)"
                              v-smart-img.noFade
                              :src="pngUrl('frameWinner')"
                              alt=""
                              style="
                                position: absolute;
                                top: 0;
                                left: 0;
                                z-index: 3;
                                display: block;
                                width: 100%;
                                object-fit: contain;
                                pointer-events: none;
                              "
                            />
                          </div>
                          <div
                            style="
                              max-width: 100%;
                              overflow: hidden;
                              color: #fff;
                              font-size: 1em;
                              font-weight: 500;
                              line-height: 1.2;
                              text-align: center;
                              text-overflow: ellipsis;
                              white-space: nowrap;
                            "
                          >
                            {{ betOption.name }}
                          </div>
                          <div
                            :style="`color: ${betOption.percentColor}; font-size: 1em; font-weight: 500; line-height: 1;`"
                          >
                            {{ formatMatchPercent(betOption.percent) }}
                          </div>
                        </div>

                        <!-- 押注选项金额信息：上方选项奖池、分割线、下方用户累计下注额 -->
                        <div
                          style="
                            width: 100%;
                            display: flex;
                            flex-direction: column;
                            align-items: center;
                            justify-content: center;
                            gap: 1.2vw;
                            margin-top: 2vw;
                          "
                        >
                          <div style="display: flex; align-items: center; justify-content: center">
                            <img
                              v-smart-img
                              src="/src/assets/icon/Aslan/coin.png"
                              alt=""
                              style="
                                display: block;
                                width: 1.5em;
                                aspect-ratio: 1/1;
                                object-fit: cover;
                              "
                            />
                            <span
                              style="color: #fff; font-size: 1em; font-weight: 500; line-height: 1"
                            >
                              {{ betOption.poolAmount }}
                            </span>
                          </div>
                          <div style="width: 100%; height: 1px; background: #e9d089"></div>
                          <div style="display: flex; align-items: center; justify-content: center">
                            <img
                              v-smart-img
                              src="/src/assets/icon/Aslan/coin.png"
                              alt=""
                              style="
                                display: block;
                                width: 1.5em;
                                aspect-ratio: 1/1;
                                object-fit: cover;
                              "
                            />
                            <span
                              style="color: #fff; font-size: 1em; font-weight: 500; line-height: 1"
                            >
                              {{ betOption.myBetAmount }}
                            </span>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                  <!-- 总奖池入口：Ended 列表同样进入赛事详情页查看结果和押注状态 -->
                  <div :style="totalPrizePoolStyle" @click="handleOpenEventDetail(matchItem)">
                    <div style="display: flex; align-items: center; gap: 1vw; min-width: 0">
                      <span
                        style="color: #fff; font-size: 1em; font-weight: 600; white-space: nowrap"
                      >
                        TOTAL PRIZE POOL
                      </span>
                      <img
                        v-smart-img
                        src="/src/assets/icon/Aslan/coin.png"
                        alt=""
                        style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
                      />
                      <span style="color: #ffe083; font-size: 1em; font-weight: 700">
                        {{ matchItem.totalPoolFormat || matchItem.totalPool || 0 }}
                      </span>
                    </div>
                    <img
                      v-smart-img.noFade
                      :src="pngUrl('rightBt')"
                      alt=""
                      style="display: block; width: 2em; flex: 0 0 auto"
                    />
                  </div>
                </div>
              </template>
            </div>
          </div>
        </itemCenter>
      </section>

      <!-- 底部占位模块：固定给贴底“我的排名”预留空间，避免遮挡主内容 -->
      <div style="width: 100vw; height: 20vw; flex: 0 0 auto"></div>
    </main>

    <!-- 我的排名贴底模块：固定在视口底部，展示当前用户排名信息 -->
    <itemCenter
      v-if="!isLoading"
      style="position: fixed; left: 0; bottom: 0; z-index: 10; width: 100vw; min-height: 21vw; max-height: 22vw"
      :imgUrl="pngUrl('myRankingBg')"
      contentStyle="padding: 2vw 8vw; box-sizing: border-box; justify-content: space-between;"
    >
      <!-- 我的排名用户信息区：结构参考 GulbenFestival 的 Personal Rank / Ranking 贴底模块 -->
      <div style="flex: 1; min-width: 0; display: flex; align-items: center; gap: 2vw">
        <div style="color: #fff; font-size: 1em; font-weight: 700; white-space: nowrap">
          {{ myRanking.rank || 999 }}
        </div>
        <img
          :src="myRanking.avatarUrl || ''"
          alt=""
          style="
            display: block;
            width: 4em;
            aspect-ratio: 1 / 1;
            border-radius: 50%;
            object-fit: cover;
          "
          @error="handleAvatarImageError"
        />
        <!-- 我的排名名称和等级：个人榜展示昵称以及 VIP/魅力/财富等级 -->
        <div style="flex: 1; min-width: 0">
          <div
            style="
              color: #fff;
              font-size: 1em;
              font-weight: 860;
              overflow: hidden;
              white-space: nowrap;
              text-overflow: ellipsis;
            "
          >
            {{ myRanking.name }}
          </div>
          <div style="display: flex; align-items: center; gap: 1vw; margin-top: 0.5vw">
            <img
              v-if="getVipLevelUrl(myRanking.vipLevelName)"
              v-smart-img.noFade
              :src="getVipLevelUrl(myRanking.vipLevelName)"
              alt=""
              style="width: 12vw; display: block"
            />
            <itemCenter
              :imgUrl="pngUrl(getLevelBgImageName('userLevel', myRanking.charmLevel))"
              style="width: 12vw; min-height: 7vw; max-height: 8vw; margin: 0; padding: 0"
              contentStyle="padding: 0 0 0 5vw; align-items: center; justify-content: center;"
            >
              <div style="color: #fff; font-size: 1em; font-weight: 700; line-height: 1">
                {{ myRanking.charmLevel || 0 }}
              </div>
            </itemCenter>
            <itemCenter
              :imgUrl="pngUrl(getLevelBgImageName('wealthLevel', myRanking.wealthLevel))"
              style="width: 12vw; min-height: 6vw; max-height: 7vw; margin: 0; padding: 0"
              contentStyle="padding: 0 0 0 4vw; align-items: center; justify-content: center;"
            >
              <div style="color: #fff; font-size: 1em; font-weight: 700; line-height: 1">
                {{ myRanking.wealthLevel || 0 }}
              </div>
            </itemCenter>
          </div>
        </div>
      </div>

      <!-- 我的排名贡献值：展示 currentUserRank 的 quantity 归一化结果 -->
      <div
        style="
          display: flex;
          align-items: center;
          justify-content: center;
          gap: 0.8vw;
          color: #fff;
          font-size: 1em;
          font-weight: 700;
          line-height: 1;
          white-space: nowrap;
        "
      >
        <img
          v-smart-img
          src="/src/assets/icon/Aslan/coin.png"
          alt=""
          style="display: block; width: 1.5em; aspect-ratio: 1/1; object-fit: cover"
        />
        {{ myRanking.amount || 0 }}
      </div>
    </itemCenter>

    <!-- 奖励弹窗模块：统一使用公共 MaskLayer 锁定背景滚动，点击上下空白关闭 -->
    <MaskLayer :maskLayerShow="showRewardPopup">
      <div
        v-if="showRewardPopup"
        style="
          width: 100vw;
          height: 100vh;
          display: flex;
          align-items: flex-start;
          justify-content: center;
          padding: 10vh 0;
          box-sizing: border-box;
        "
        @click.self="handleCloseRewardPopup"
      >
        <!-- 奖励弹窗内容：rewardBg 靠上展示，上下保留遮罩空白用于点击退出 -->
        <itemCenter
          style="width: 100vw; min-height: 225vw; max-height: 226vw"
          :imgUrl="pngUrl('rewardBg')"
          contentStyle="display: flex; flex-direction: column;justify-content: flex-start; gap: 12.5vw; padding: 34vw 6vw 0vw; box-sizing: border-box;"
        >
          <!-- 前三名奖励列表：从上往下依次展示第 1、2、3 名奖励 -->
          <div
            v-for="rankReward in rewardPopupList"
            :key="rankReward.rankRange"
            style="
              width: 100%;
              display: flex;
              align-items: flex-start;
              justify-content: center;
              gap: 2vw;
              box-sizing: border-box;
            "
          >
            <!-- 左侧重点奖励：使用背景图内置奖励框，只占位并居中奖励图 -->
            <div
              v-if="rankReward.rewards[0]"
              style="
                width: 49%;
                display: flex;
                flex-direction: column;
                align-items: center;
                gap: 1vw;
                box-sizing: border-box;
              "
            >
              <!-- 左侧奖励图片占位：按设计稿奖励框比例展示金币图 -->
              <div
                style="
                  width: 100%;
                  aspect-ratio: 158.634/175.179;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  box-sizing: border-box;
                "
              >
                <img
                  :src="rankReward.rewards[0].cover || ''"
                  alt=""
                  style="display: block; width: 72%; aspect-ratio: 1/1; object-fit: contain"
                  @error="(event) => handleRewardImageError(event, rankReward.rewards[0].type)"
                />
              </div>

              <!-- 左侧奖励数量：复用通用奖励格式化展示规则 -->
              <div
                style="
                  width: 100%;
                  height: 5vw;
                  display: flex;
                  align-items: center;
                  justify-content: center;
                  color: #fff;
                  font-size: 1.2em;
                  font-weight: 590;
                  color: #ffe090;
                  text-align: center;
                  white-space: nowrap;
                "
              >
                {{ showRewardDetail(rankReward.rewards[0].type, rankReward.rewards[0]) }}
              </div>
            </div>

            <!-- 右侧四个奖励：两行两列铺满剩余空间 -->
            <div
              style="
                flex: 1;
                display: grid;
                grid-template-columns: repeat(2, minmax(0, 1fr));
                gap: 0 1.5vw;
                box-sizing: border-box;
              "
            >
              <!-- 右侧单个奖励项：奖励图和奖励信息纵向居中展示 -->
              <div
                v-for="(reward, rewardIndex) in rankReward.rewards.slice(1)"
                :key="rewardIndex"
                style="
                  width: 100%;
                  display: flex;
                  flex-direction: column;
                  align-items: center;
                  gap: 0vw;
                  box-sizing: border-box;
                "
              >
                <!-- 右侧奖励图片占位：背景图已有奖励框，这里只负责放图 -->
                <div
                  style="
                    width: 100%;
                    aspect-ratio: 1/1;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    box-sizing: border-box;
                  "
                >
                  <img
                    :src="reward.cover || ''"
                    alt=""
                    style="display: block; width: 68%; aspect-ratio: 1/1; object-fit: contain"
                    @error="(event) => handleRewardImageError(event, reward.type)"
                  />
                </div>

                <!-- 右侧奖励数量：展示金币数量等格式化内容 -->
                <div
                  style="
                    width: 100%;
                    height: 6.5vw;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    color: #fff;
                    font-size: 1.2em;
                    font-weight: 590;
                    color: #ffe090;
                    text-align: center;
                    white-space: nowrap;
                  "
                >
                  {{ showRewardDetail(reward.type, reward) }}
                </div>
              </div>
            </div>
          </div>
        </itemCenter>
      </div>
    </MaskLayer>

    <!-- 规则弹窗模块：点击头部 ruleBt 后展示，统一使用 MaskLayer 并预留上下空白关闭 -->
    <MaskLayer :maskLayerShow="showRulePopup">
      <div
        v-if="showRulePopup"
        style="
          width: 100vw;
          height: 100vh;
          display: flex;
          align-items: flex-start;
          justify-content: center;
          padding: 10vh 0;
          box-sizing: border-box;
        "
        @click.self="handleCloseRulePopup"
      >
        <!-- 规则弹窗内容：ruleBg 高度较长，宽度占满 100vw，顶部和底部空白用于点击退出 -->
        <itemCenter
          style="width: 100vw; min-height: 178vw; max-height: 179vw"
          :imgUrl="pngUrl('ruleBg')"
          contentStyle="padding: 0; box-sizing: border-box;"
        />
      </div>
    </MaskLayer>
  </div>
</template>

<script setup>
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import { getPngUrl } from '@/config/imagePaths.js'
import { preloadImages } from '@/utils/image/imagePreloader.js'
import { apiPostWorldCupMatchList, apiPostWorldCupRankList } from '@/api/worldCup.js'
import { viewUserInfo } from '@/utils/appBridge.js'
import { connectToApp } from '@/utils/appConnector.js'
import { handleAvatarImageError, handleRewardImageError } from '@/utils/image/imageHandler.js'
import { formatRewardDisplay } from '@/utils/rewardFormatter.js'
import MaskLayer from '@/components/MaskLayer.vue'
import itemCenter from '@/components/itemCenter.vue'
import TopUser from './components/topUser.vue'

const assetPath = 'Activities/WorldCup/'
const pngUrl = (filename) => getPngUrl(assetPath, filename)
const coinIcon = new URL('/src/assets/icon/Aslan/coin.png', import.meta.url).href
const router = useRouter()
const isLoading = ref(true)
const ranking = ref([])
const myRanking = ref({})
const activeMatchTab = ref(0)
const predictMatchList = ref([])
const endedMatchList = ref([])
const matchListRequestTokenMap = {
  0: 0,
  1: 0,
}
// 控制第四名以后的排行榜是否展开，默认只展示前三名和 Show All Users。
const showRankingList = ref(false)
// 控制奖励弹窗显示，点击 giftBt 打开，点击弹窗遮罩关闭。
const showRewardPopup = ref(false)
// 控制规则弹窗显示，点击 ruleBt 打开，点击弹窗上下空白区域关闭。
const showRulePopup = ref(false)

// 奖励弹窗静态数据：暂未配置 templateId，先仿照 BountyFootball 的奖励结构展示金币奖励。
const rewardPopupList = ref(
  [1, 2, 3].map((rankRange) => ({
    rankRange,
    rewards: Array.from({ length: 5 }, () => ({
      type: 'GOLD',
      cover: coinIcon,
      content: '1',
      quantity: 1,
    })),
  })),
)

const blockingImages = [
  'bg2',
  'bg',
  'ruleBt',
  'ruleBg',
  'EventlistBg',
  'matchBg',
  'drawSign',
  'frameWinner',
  'numPeople',
  'rightBt',
  'RankingMain',
  'RankingItem',
  'RankingBottomBorder',
  'myRankingBg',
  'giftBt',
  'rewardBg',
  'showMoreBt',
  'frameTop1',
  'frameTop2',
  'frameTop3',
  'vip1',
  'userLevel1Bg',
  'wealthLevel1Bg',
  'vip2',
  'vip3',
  'vip4',
  'vip5',
  'vip6',
  'userLevel2Bg',
  'userLevel3Bg',
  'userLevel4Bg',
  'userLevel5Bg',
  'wealthLevel2Bg',
  'wealthLevel3Bg',
  'wealthLevel4Bg',
  'wealthLevel5Bg',
]

const emptyTopUsers = [
  {
    avatarUrl: '',
    name: '',
    userId: '',
    account: '',
    amount: '',
    wealthLevel: 0,
    charmLevel: 0,
    vipLevelName: 'VISCOUNT',
  },
  {
    avatarUrl: '',
    name: '',
    userId: '',
    account: '',
    amount: '',
    wealthLevel: 0,
    charmLevel: 0,
    vipLevelName: 'VISCOUNT',
  },
  {
    avatarUrl: '',
    name: '',
    userId: '',
    account: '',
    amount: '',
    wealthLevel: 0,
    charmLevel: 0,
    vipLevelName: 'VISCOUNT',
  },
]

const topUsers = computed(() => {
  const result = ranking.value.slice(0, 3)
  return [...result, ...emptyTopUsers].slice(0, 3)
})

const rankingListAfterTop3 = computed(() => ranking.value.slice(3))

// 展示更多入口控制：只有第四名以后存在排行榜数据时才展示按钮和展开列表。
const hasRankingListAfterTop3 = computed(() => rankingListAfterTop3.value.length > 0)
const showMoreRankingEntry = computed(() => !showRankingList.value && hasRankingListAfterTop3.value)
const showExpandedRankingList = computed(
  () => showRankingList.value && hasRankingListAfterTop3.value,
)

const matchTabActiveButtonStyle =
  'width: 50%; display: flex; justify-content: center; align-items: center; padding: 9.437px; box-sizing: border-box; border-radius: 7.549px; border: 0.944px solid #E9D089; background: linear-gradient(180deg, rgba(79, 77, 33, 0.50) 0%, rgba(79, 77, 33, 0.00) 100%); backdrop-filter: blur(13.449894905090332px);'
const matchTabInactiveButtonStyle =
  'width: 50%; display: flex; justify-content: center; align-items: center; padding: 9.437px; box-sizing: border-box;'
const matchTabActiveTextStyle = 'color: #FFE083; font-weight: 500; font-size: 1em;'
const matchTabInactiveTextStyle = 'color: #E9CB78; font-weight: 400; font-size: 1em;'
const endedMatchItemStyle =
  'width: 100%; flex: 0 0 auto; display: flex; flex-direction: column; justify-content: space-between; align-items: center; gap: 3vw; box-sizing: border-box; border-radius: 10.682px; border: 0.89px solid #5D6948; background: linear-gradient(180deg, #0B2415 0%, #051C12 100%); backdrop-filter: blur(12.687064170837402px); overflow: hidden;'
const endedBetOptionDefaultStyle =
  'flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; align-items: center; padding: 2vw 1.5vw; box-sizing: border-box; border-radius: 7.121px; border: 0.445px solid #E9D089; background: linear-gradient(180deg, rgba(79, 77, 33, 0.50) 0%, rgba(79, 77, 33, 0.00) 100%); backdrop-filter: blur(11.97230052947998px);'
const endedBetOptionSelectedStyle =
  'flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; align-items: center; padding: 2vw 1.5vw; box-sizing: border-box; border-radius: 7.121px; border: 1px solid #FFFA5D; background: linear-gradient(180deg, rgba(79, 77, 33, 0.50) 0%, rgba(79, 77, 33, 0.00) 100%); backdrop-filter: blur(11.97230052947998px); box-shadow: -0.223px -0.223px 0.89px 0 #D6C100, 0.223px 0.223px 0.89px 0 #D6C100, 0 0 2.67px 0 rgba(255, 250, 93, 0.60), 0 0 4.451px 0 rgba(255, 250, 93, 0.40), 0 0 3.561px 0 rgba(210, 204, 0, 0.30);'
const totalPrizePoolStyle =
  'width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 2vw; padding: 2vw 3vw; box-sizing: border-box; border-radius: 7.549px; border: 0.472px solid #E9D089; background: linear-gradient(180deg, rgba(79, 77, 33, 0.50) 0%, rgba(79, 77, 33, 0.00) 100%); backdrop-filter: blur(12.692154884338379px);'

// 赛事列表切换按钮样式：根据当前 tab 返回选中或未选中的内联样式。
const getMatchTabButtonStyle = (tab) => {
  return activeMatchTab.value === tab ? matchTabActiveButtonStyle : matchTabInactiveButtonStyle
}

// 赛事列表切换按钮文字样式：选中态和未选中态字体颜色、粗细不同。
const getMatchTabTextStyle = (tab) => {
  return activeMatchTab.value === tab ? matchTabActiveTextStyle : matchTabInactiveTextStyle
}

const vipLevelImageMap = {
  VISCOUNT: 'vip1',
  EARL: 'vip2',
  MARQUIS: 'vip3',
  DUKE: 'vip4',
  KING: 'vip5',
  EMPEROR: 'vip6',
}

// VIP 等级图片映射：规则同步 GulbenFestival 的 Personal Rank / Ranking。
const getVipLevelImageName = (vipLevelName = '') => {
  return vipLevelImageMap[String(vipLevelName || '').toUpperCase()] || ''
}

// 只在接口返回有效 VIP 等级时展示对应图片。
const getVipLevelUrl = (vipLevelName = '') => {
  const imageName = getVipLevelImageName(vipLevelName)
  return imageName ? pngUrl(imageName) : ''
}

// 魅力等级和财富等级每 10 级一档，最高使用第 5 档背景。
const getLevelBgImageName = (prefix, level) => {
  const levelValue = Number(level) || 0
  const imageIndex = Math.min(5, Math.max(1, Math.ceil(levelValue / 10) || 1))

  return `${prefix}${imageIndex}Bg`
}

// 排行榜字段归一化：对接世界杯排行榜接口返回的 rankingList/currentUserRank 字段。
const normalizeRankingItem = (item = {}) => {
  return {
    ...item,
    rank: item.rank ?? '',
    userId: item.userId ?? '',
    avatarUrl: item.avatar ?? '',
    name: item.nickname ?? '',
    amount: item.quantity ?? 0,
    quantityNumber: item.quantityNumber ?? 0,
    account: item.account ?? '',
    specialAccount: item.specialAccount ?? '',
    encryptedId: item.encryptedId ?? '',
    wealthLevel: item.wealthLevel ?? 0,
    charmLevel: item.charmLevel ?? 0,
    vipLevelName: item.vipLevelName ?? '',
  }
}

// 赛事列表字段归一化：只按照 apiPostWorldCupMatchList 当前返回字段生成页面数据。
const normalizeMatchItem = (item = {}) => {
  return {
    matchId: item.matchId == null ? '' : String(item.matchId),
    homeTeam: item.homeTeam ?? '',
    awayTeam: item.awayTeam ?? '',
    homeFlag: item.homeFlag ?? '',
    awayFlag: item.awayFlag ?? '',
    kickoffTime: item.kickoffTime ?? 0,
    status: item.status ?? 0,
    result: item.result ?? null,
    totalPool: item.totalPool ?? 0,
    totalPoolFormat: item.totalPoolFormat ?? '',
    homePercent: item.homePercent ?? 0,
    drawPercent: item.drawPercent ?? 0,
    awayPercent: item.awayPercent ?? 0,
    joinCount: item.joinCount ?? 0,
    joined: item.joined ?? false,
    betOption: item.betOption ?? item.myBetOption ?? null,
    betStatus: item.betStatus ?? null,
    payout: item.myPayout ?? item.payout ?? item.winAmount ?? 0,
    betAmount: item.betAmount ?? item.myBetAmount ?? 0,
    homePool: item.homePool ?? 0,
    drawPool: item.drawPool ?? 0,
    awayPool: item.awayPool ?? 0,
    homePoolFormat: item.homePoolFormat ?? '',
    drawPoolFormat: item.drawPoolFormat ?? '',
    awayPoolFormat: item.awayPoolFormat ?? '',
    myHomeBetFormat: item.myHomeBetFormat ?? null,
    myDrawBetFormat: item.myDrawBetFormat ?? null,
    myAwayBetFormat: item.myAwayBetFormat ?? null,
  }
}

// 赛事状态文案：根据接口 status 字段展示未开赛、比赛中或已结束。
const getMatchStatusText = (status) => {
  const statusMap = {
    0: 'Not Started',
    1: 'In Progress',
    2: 'Ended',
  }

  return statusMap[Number(status)] || ''
}

// Predict Now 状态类型：比赛中已参与、比赛中未参与、未开赛三种卡片左上角展示。
const getPredictMatchBadgeType = (matchItem = {}) => {
  if (Number(matchItem.status) === 1 && matchItem.joined) return 'joined'
  if (Number(matchItem.status) === 1 && !matchItem.joined) return 'notJoined'
  return 'kickoff'
}

// UTC+8 开赛时间格式化：未开赛卡片左上角展示 Kick-off 文案。
const formatKickoffTime = (kickoffTime) => {
  const timestamp = Number(kickoffTime)
  if (!timestamp) return '--:--'

  const utc8Date = new Date(timestamp + 8 * 60 * 60 * 1000)
  const hours = String(utc8Date.getUTCHours()).padStart(2, '0')
  const minutes = String(utc8Date.getUTCMinutes()).padStart(2, '0')
  return `${hours}:${minutes}`
}

// Predict Now 状态文案：按比赛状态和 joined 字段生成左上角文本。
const getPredictMatchBadgeText = (matchItem = {}) => {
  const badgeType = getPredictMatchBadgeType(matchItem)
  if (badgeType === 'joined') return 'join'
  if (badgeType === 'notJoined') return 'Not Joined'
  return `Kick-off: ${formatKickoffTime(matchItem.kickoffTime)}(UTC+8)`
}

// Predict Now 状态样式：已参与、未参与、未开赛使用不同视觉状态。
const getPredictMatchBadgeStyle = (matchItem = {}) => {
  const baseStyle =
    'min-height: 6.6vw; display: flex; align-items: center; gap: 1vw; padding: 1vw 2vw; box-sizing: border-box; color: #FFF; font-size: 1em; font-weight: 500; line-height: 1; white-space: nowrap;'
  const badgeType = getPredictMatchBadgeType(matchItem)

  if (badgeType === 'joined') {
    return `${baseStyle} border-radius: 6.606px 0; background: linear-gradient(152deg, #31FB5E 7.01%, #21B843 92.99%);`
  }
  if (badgeType === 'notJoined') {
    return `${baseStyle} border-radius: 6.606px 0; background: linear-gradient(135deg, #A2A2A2 2.82%, #646464 99.15%);`
  }

  return `${baseStyle} border-radius: 6.606px 0;background: linear-gradient(152deg, #FFA970 7.01%, #FF8F26 92.99%);`
}

// 赛事占比展示：接口返回数字时补百分号，已带百分号的字符串直接展示。
const formatMatchPercent = (percent) => {
  if (typeof percent === 'string' && percent.includes('%')) return percent
  const percentValue = percent === '' || percent === null || percent === undefined ? 0 : percent
  return `${percentValue}%`
}

// Ended 状态类型：当前比赛列表接口没有用户押注结果明细，中奖状态先兼容后续可能补充的 payout/betStatus 字段。
const getEndedMatchStatusType = (matchItem = {}) => {
  if (!matchItem.joined) return 'notJoined'
  if (Number(matchItem.payout) > 0 || Number(matchItem.betStatus) === 1) return 'win'
  return 'lost'
}

// Ended 状态文案：未中奖和未参与使用固定文案，中奖状态在模板中展示金币和金额。
const getEndedMatchBadgeText = (matchItem = {}) => {
  const statusType = getEndedMatchStatusType(matchItem)
  if (statusType === 'notJoined') return 'Not Joined'
  return 'Better luck next time'
}

// Ended 中奖金额：接口暂未在比赛列表中返回派彩金额，当前没有字段时展示 0。
const getEndedMatchWinAmount = (matchItem = {}) => {
  return matchItem.payout || 0
}

// Ended 状态样式：参与中奖、参与未中奖、未参与分别使用不同背景。
const getEndedMatchBadgeStyle = (matchItem = {}) => {
  const baseStyle =
    'min-height: 7vw; display: flex; align-items: center; gap: 1vw; padding: 1vw 2vw; box-sizing: border-box; color: #FFF; font-size: 1em; font-weight: 500; line-height: 1; white-space: nowrap; border-radius: 11px 0;'
  const statusType = getEndedMatchStatusType(matchItem)

  if (statusType === 'win') {
    return `${baseStyle} background: linear-gradient(152deg, #31FB5E 7.01%, #21B843 92.99%);`
  }
  if (statusType === 'notJoined') {
    return `${baseStyle} background: linear-gradient(135deg, #484646 2.82%, #292424 99.15%);`
  }

  return `${baseStyle} background: linear-gradient(135deg, #A2A2A2 2.82%, #646464 99.15%);`
}

// Ended 押注项数据：上方展示各选项奖池格式化金额，下方展示当前用户累计下注额。
const getEndedBetOptions = (matchItem = {}) => {
  return [
    {
      option: 1,
      flagUrl: matchItem.homeFlag,
      isOssImage: false,
      name: matchItem.homeTeam,
      percent: matchItem.homePercent,
      percentColor: '#71ce6e',
      myBetAmount: matchItem.myHomeBetFormat || 0,
      poolAmount: matchItem.homePoolFormat || matchItem.homePool || 0,
    },
    {
      option: 2,
      flagUrl: pngUrl('drawSign'),
      isOssImage: true,
      name: 'DRAW',
      percent: matchItem.drawPercent,
      percentColor: '#a0a181',
      myBetAmount: matchItem.myDrawBetFormat || 0,
      poolAmount: matchItem.drawPoolFormat || matchItem.drawPool || 0,
    },
    {
      option: 3,
      flagUrl: matchItem.awayFlag,
      isOssImage: false,
      name: matchItem.awayTeam,
      percent: matchItem.awayPercent,
      percentColor: '#71ce6e',
      myBetAmount: matchItem.myAwayBetFormat || 0,
      poolAmount: matchItem.awayPoolFormat || matchItem.awayPool || 0,
    },
  ]
}

// Ended 押注项选中态：用户在对应选项存在累计下注额时高亮该押注项，支持多选项同时高亮。
const isEndedBetOptionSelected = (matchItem = {}, option) => {
  if (!matchItem.joined) return false
  const selectedBetMap = {
    1: matchItem.myHomeBetFormat,
    2: matchItem.myDrawBetFormat,
    3: matchItem.myAwayBetFormat,
  }
  const selectedBetAmount = selectedBetMap[Number(option)]
  return selectedBetAmount !== null && selectedBetAmount !== undefined && selectedBetAmount !== ''
}

// Ended 胜方标识：根据 result 字段给主胜、平局或客胜对应押注项叠加 frameWinner。
const isEndedBetOptionWinner = (matchItem = {}, option) => {
  return Number(matchItem.result) === Number(option)
}

// Ended 押注项样式：用户押注过的选项展示选中态，未押注选项展示默认样式。
const getEndedBetOptionStyle = (matchItem = {}, option) => {
  return isEndedBetOptionSelected(matchItem, option)
    ? endedBetOptionSelectedStyle
    : endedBetOptionDefaultStyle
}

// 获取世界杯排行榜：使用世界杯专用接口，接口无业务参数但 POST 仍传空对象。
const getPersonalRanking = async () => {
  try {
    const resRanking = await apiPostWorldCupRankList()
    const rankBody = resRanking.body || resRanking

    if (rankBody) {
      myRanking.value = normalizeRankingItem(rankBody.currentUserRank || {})
      ranking.value = (rankBody.rankingList || []).map((item) => normalizeRankingItem(item))
      if (!hasRankingListAfterTop3.value) {
        showRankingList.value = false
      }
      return
    }

    ranking.value = []
    myRanking.value = {}
  } catch (error) {
    console.error('WorldCup 排行榜加载失败:', error)
    ranking.value = []
    myRanking.value = {}
  }
}

// 写入赛事列表数据：Predict Now 和 Ended 分开承载，避免两个列表切换时数据混用。
const setMatchListByTab = (tab, records = []) => {
  const normalizedList = records.map((item) => normalizeMatchItem(item))
  if (Number(tab) === 0) {
    predictMatchList.value = normalizedList
    return
  }

  endedMatchList.value = normalizedList
}

// 清空赛事列表数据：只清理当前请求对应的列表，不影响另一个 tab 的缓存数据。
const clearMatchListByTab = (tab) => {
  if (Number(tab) === 0) {
    predictMatchList.value = []
    return
  }

  endedMatchList.value = []
}

// 获取世界杯赛事列表：默认 size 固定为 10，tab=0 为 Predict Now，tab=1 为 Ended。
const getWorldCupMatchList = async (tab = activeMatchTab.value) => {
  const requestTab = Number(tab)
  const currentRequestToken = ++matchListRequestTokenMap[requestTab]

  try {
    const resMatch = await apiPostWorldCupMatchList({
      size: 10,
      current: 1,
      tab: requestTab,
    })
    const matchBody = resMatch.body || resMatch

    if (currentRequestToken !== matchListRequestTokenMap[requestTab]) return
    setMatchListByTab(requestTab, matchBody.records || [])
  } catch (error) {
    console.error('WorldCup 赛事列表加载失败:', error)
    if (currentRequestToken !== matchListRequestTokenMap[requestTab]) return
    clearMatchListByTab(requestTab)
  }
}

// 点击排行榜用户时打开 App 内用户资料页。
const handleRankingClick = (rankingItem = {}) => {
  if (!rankingItem.userId) return
  viewUserInfo(rankingItem.userId)
}

// 切换赛事列表 tab：每次切换 Predict Now / Ended 都重新请求赛事列表。
const handleMatchTabClick = async (tab) => {
  if (activeMatchTab.value === tab) return
  activeMatchTab.value = tab
  await getWorldCupMatchList(tab)
}

// 打开赛事详情页：总奖池入口跳转，详情页后续负责赛事详情和押注服务。
const handleOpenEventDetail = (matchItem = {}) => {
  if (!matchItem.matchId) return
  router.push({
    path: '/activities/world-cup/event-detail',
    query: {
      matchId: matchItem.matchId,
    },
  })
}

// 展开第四名以后排行榜列表，点击 Show All Users 时触发。
const handleShowRankingList = () => {
  if (!hasRankingListAfterTop3.value) return
  showRankingList.value = true
}

// 收起第四名以后排行榜列表，点击 Collapse List 时触发。
const handleCollapseRankingList = () => {
  showRankingList.value = false
}

// 奖励内容展示格式：复用项目通用奖励格式化逻辑，保持和 BountyFootball 一致。
const showRewardDetail = (type, reward) => {
  return formatRewardDisplay(type, reward)
}

// 打开奖励弹窗，入口为 RankingMain 右上角 giftBt。
const handleOpenRewardPopup = () => {
  showRewardPopup.value = true
}

// 关闭奖励弹窗，当前先通过点击遮罩触发。
const handleCloseRewardPopup = () => {
  showRewardPopup.value = false
}

// 打开规则弹窗，入口为头部右侧 ruleBt。
const handleOpenRulePopup = () => {
  showRulePopup.value = true
}

// 关闭规则弹窗，点击规则弹窗上下预留空白区域触发。
const handleCloseRulePopup = () => {
  showRulePopup.value = false
}

// 页面初始化接口：连接 App 并写入请求头后，再独立拉取排行榜和默认赛事列表。
const loadInitialWorldCupData = async () => {
  await Promise.all([getPersonalRanking(), getWorldCupMatchList()])
}

// 首屏预加载：只处理阻塞图片，不等待接口数据返回。
const completePreloading = async () => {
  try {
    await preloadImages(blockingImages.map((imageName) => pngUrl(imageName)))
  } catch (error) {
    console.error('WorldCup 图片预加载过程中发生错误:', error)
  } finally {
    isLoading.value = false
  }
}

// 连接 App 并设置接口请求头：所有业务接口必须在 connectToApp 成功后再请求。
const connectToAppHandler = async () => {
  await connectToApp(() => {
    loadInitialWorldCupData()
  })
}

onMounted(() => {
  completePreloading()
  connectToAppHandler()
})
</script>

<style lang="scss" scoped>
.full-page::-webkit-scrollbar {
  display: none;
}

/* 页面所有模块隐藏可见滚动条，保留必要滚动能力但不露出滚动条样式。 */
.full-page,
.full-page * {
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.full-page *::-webkit-scrollbar {
  display: none;
}

.ranking-name,
.ranking-id {
  width: 100%;
  overflow: hidden;
  color: #fff;
  font-size: 1em;
  line-height: 1.1;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ranking-name {
  font-weight: 800;
}

.ranking-id {
  font-weight: 600;
  opacity: 0.88;
}

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

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

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

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