<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted } from "vue";
import DesignStage from "../../../components/DesignStage.vue";
import type Player from "@/commons/player.ts";
import { $is_local_mode } from "@/commons/utils.ts";
import { cssAssetUrl, assetUrl } from "@/commons/assets.ts";
import { playApplauseMusic, stopApplauseMusic } from "@/commons/music";
const defaultAvatarUrl = assetUrl("game4/default-avator.webp");

const props = defineProps<{
  rankList: Player[];
  /** H5 玩家操控产生的加速度: { [userid]: boost(叠加系数, 0~N) } */
  horseBoosts: Record<string, number>;
}>();

const emit = defineEmits<{
  start: [];
  next: [];
  back: [];
}>();

const designStage = ref<InstanceType<typeof DesignStage> | null>(null);

const imageUrls = {
  bgTop: cssAssetUrl("game4/bg-top.webp"),
  bgBottom: cssAssetUrl("game4/bg-bottom.webp"),
  logo: cssAssetUrl("game1/logo.png"),
  titleBg: cssAssetUrl("game4/horse-title-bg.webp"),
  bigBrum: cssAssetUrl("game4/big-brum.webp"),
  username: cssAssetUrl("game4/username.svg"),
  avatar: cssAssetUrl("game4/default-avator.webp"),
  resultBg: cssAssetUrl("game4/resultbg.webp"),
  next: cssAssetUrl("game1/next.png"),
  back: cssAssetUrl("game1/back.png"),
  // 结果弹窗 - podium 相关资源（复用 game1）
  podium: cssAssetUrl("game4/podium.webp"),
  fireworks: cssAssetUrl("game1/fireworks.png"),
  guan1: cssAssetUrl("game1/guan1.png"),
  pai1: cssAssetUrl("game4/pai1.webp"),
  guan2: cssAssetUrl("game1/guan2.png"),
  pai2: cssAssetUrl("game4/pai2.webp"),
  guan3: cssAssetUrl("game1/guan3.png"),
  pai3: cssAssetUrl("game4/pai3.webp"),
  rankIcon: cssAssetUrl("game1/no-icon.png"),
  avatarAnimation: cssAssetUrl("avatar_animation.png"),
};

// ========== 速度基准（满速马在游戏结束前 1~2 秒刚好跑到右边缘）==========
// MAX_PULSE=2.5 → 最大倍率 = 1+2.5 = 3.5x
// BASE_DURATION_SEC = 240 → 基准速度 0.417%/s
// 全程最大 boost: 0.417*3.5*60 = 87.5%（理论），实测约 58 秒到右边缘
// 不加速(boost=0):  0.417*60 = 25% → 时间地板推到 55%
// 一般活动(boost≈1): 0.417*2*60 = 50% → 地板 55%
// 活跃玩家(boost≈2): 0.417*3*60 = 75% → 大幅领先
const TOTAL_DISTANCE_PX = 2160; // -120px ~ 2040px
const BASE_DURATION_SEC = 240;
const BASE_SPEED_PERCENT_PER_SEC = 100 / BASE_DURATION_SEC; // ≈ 0.417%/s 基准速度

// 马匹帧配置（使用 game3 的马匹）
const HORSE_SIZE = 280;
const horseFrameConfigs = [
    { type: 1, dir: 'game3/ma1', prefix: '1ma_', startIndex: 24, count: 12 },
    { type: 2, dir: 'game3/ma2', prefix: '2ma_', startIndex: 24, count: 12 },
    { type: 3, dir: 'game3/ma3', prefix: '3ma_', startIndex: 12, count: 14 },
];

const HORSE_TYPES = [1, 2, 3] as const;

const horseFrames: Record<number, string[]> = {};
const horseFrameCount: Record<number, number> = {};
for (const config of horseFrameConfigs) {
    horseFrames[config.type] = Array.from({ length: config.count }, (_, i) =>
        assetUrl(`${config.dir}/${config.prefix}${String(config.startIndex + i).padStart(5, '0')}.png`),
    );
    horseFrameCount[config.type] = config.count;
}

const HORSE_FRAME_TICK_MS = 24; // ~40fps

// ========== 速度/加速机制 ==========
// H5 每次摇一摇 → WebSocket 推送累计总分 → 按总分比例直接计算 boost
// 高分跑快、低分跑慢：boost = (自身分数 / 当前最高分) × MAX_PULSE
// 最高分玩家 boost=MAX_PULSE=2.5（即 3.5x 基准速度 ≈ 58 秒到右边缘，对标 mock 满速马）
const MAX_PULSE = 2.5; // 最大加速倍率上限
const BOOST_DECAY = 0.994; // 每帧衰减系数（停止摇一摇后逐渐减速，半衰期约 1.9s）

/** 瞬时加速值: { [userid]: currentBoost }，每帧衰减（真实 websocket 数据专用） */
const transientBoosts = ref<Record<string, number>>({});
/** mock 模式下每匹马的固定全程 boost 值（不衰减），null 表示非 mock 模式 */
const mockFixedBoosts = ref<Record<string, number> | null>(null);

/**
 * 根据 rankList 中的累计总分数，按比例直接计算每匹马的 boost（不再使用增量）
 * - 找出所有有效玩家中的最高分
 * - 每匹马的 boost = (自身分数 / 最高分) × MAX_PULSE
 * - 最高分玩家享受 boost=2.5 满速，低分按比例减速
 */
const recalculateBoostsFromScores = (players: Player[]) => {
  if (!players || players.length === 0) return;
  if (mockFixedBoosts.value) return; // mock 模式下不干预

  // 收集有效玩家及其分数、ID
  const entries: { id: string; score: number; nickname: string }[] = [];
  players.forEach((p, index) => {
    if (!p.nickname || p.nickname === "虚位以待" || p.nickname === "-") return;
    if (p.wechat_id && String(p.wechat_id).startsWith("empty-")) return;
    const id = p.userid || p.wechat_id || (p.avatar ? `avt:${p.avatar}` : `horse-${index}`);
    const score = Number(p.score ?? 0);
    if (isNaN(score) || score <= 0) return;
    entries.push({ id, score, nickname: p.nickname || "" });
  });

  if (entries.length === 0) return;

  // 当前最高分作为满速基准
  const maxScore = Math.max(...entries.map(e => e.score));
  if (maxScore <= 0) return;

  const updated: Record<string, number> = {};
  let logLines: string[] = [];

  entries.forEach(({ id, score, nickname }) => {
    // 按比例计算：最高分→2.5，其他人等比缩放
    const boost = parseFloat(((score / maxScore) * MAX_PULSE).toFixed(2));
    updated[id] = boost;
    logLines.push(`${nickname}: score=${score} → boost=${boost.toFixed(2)}`);
  });

  transientBoosts.value = updated;
  console.log(
    `[Rank1View] 🏇 按总分比例计算 boost（最高分=${maxScore}, MAX_PULSE=${MAX_PULSE}）:\n  ${logLines.join("\n  ")}`,
  );
};

interface Horse {
  id: string;
  horseType: number;
  lane: number;
  startY: number;
  xPercent: number;
  boost: number; // boost=0 按基准60秒跑完，boost越大越快
  nickname: string;
  avatar: string;
  frameIndex: number;
  frameTimer: number;
}

interface RankItem {
  rank: number;
  userid: string;
  nickname: string;
  avatar: string;
  score: number;
}

const horses = ref<Horse[]>([]);
const isGameRunning = ref(false);
const showResult = ref(false);
const finalRankList = ref<RankItem[]>([]);
/** 补齐占位的完整 10 人排名列表 */
const fullRankList = computed<RankItem[]>(() => {
  const result: RankItem[] = [];
  for (let i = 0; i < 10; i++) {
    result.push(
      finalRankList.value[i] ?? {
        rank: i + 1,
        userid: `empty-${i}`,
        nickname: "虚位以待",
        avatar: "",
        score: 0,
      },
    );
  }
  return result;
});
/** 倒计时结束后才为 true，控制背景动画和马匹渲染 */
const gameStarted = ref(false);

/** 游戏已运行时间(ms)，用于时间比例最小进度保障（参考 game2） */
const gameElapsedMs = ref(0);
/** 时间比例最小进度百分比：确保无加速时马匹也随倒计时自然推进，但不会喧宾夺主 */
const MIN_PROGRESS_RATIO = 55; // 55% - 纯时间推进确保不落后太多，留给 boost 足够的竞争空间

// const LANE_POSITIONS = [7, 115, 235, 345, 455];
const LANE_POSITIONS = [0, 108, 228, 338, 448];

const updateHorses = (players: Player[]) => {
  console.log("[Rank1View] updateHorses 被调用，players:", players?.length, JSON.stringify(players?.slice(0, 3)));
  
  const validPlayers = players.filter((p) => {
    // 昵称必须是真实玩家
    if (!p.nickname || p.nickname === "虚位以待" || p.nickname === "-") return false;
    
    // wechat_id 不能是空占位
    if (p.wechat_id && String(p.wechat_id).startsWith("empty-")) return false;
    
    // 有 userid/wechat_id 或者有 avatar，都认为是真实玩家
    if (p.userid || p.wechat_id || p.avatar) return true;
    
    return false;
  });

  console.log("[Rank1View] 有效玩家数:", validPlayers.length, validPlayers.map(p => ({ nickname: p.nickname, userid: p.userid, wechat_id: p.wechat_id, avatar: p.avatar })));

  if (validPlayers.length === 0) {
    console.log("[Rank1View] ⚠️ 无有效玩家，不生成马匹");
    return;
  }

  // 保留已存在的 xPercent 和 boost，避免新玩家列表覆盖进度
  const existingMap = new Map(horses.value.map((h) => [h.id, h]));

  horses.value = validPlayers.map((player, index) => {
    // WebSocket 数据无 userid/wechat_id，用 avatar 作为稳定标识
    const id = player.userid || player.wechat_id || (player.avatar ? `avt:${player.avatar}` : `horse-${index}`);
    const existing = existingMap.get(id);
    const horseType = HORSE_TYPES[index % HORSE_TYPES.length]!;
    return {
      id,
      horseType,
      lane: index % LANE_POSITIONS.length,
      startY: LANE_POSITIONS[index % LANE_POSITIONS.length]!,
      xPercent: existing?.xPercent ?? 0,
      boost: existing?.boost ?? 0,
      nickname: player.nickname,
      avatar: player.avatar || "",
      frameIndex: existing?.frameIndex ?? Math.floor(Math.random() * (horseFrameCount[horseType] ?? 12)),
      frameTimer: existing?.frameTimer ?? 0,
    };
  });

  console.log("[Rank1View] ✅ 生成马匹数:", horses.value.length, horses.value.map(h => ({ id: h.id, nickname: h.nickname, startY: h.startY })));
};

const mockAvatars = [
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Felix',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Aneka',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Salem',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Midnight',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Lucky',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Bandit',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Misty',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Pepper',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Oreo',
  'https://api.dicebear.com/9.x/fun-emoji/svg?seed=Tiger',
];
const mockNicknames = ['疾风骑士', '闪电侠', '追风者', '千里马', '飞毛腿', '烈焰驹', '暴风战士', '神行者', '银鞍客', '踏雪无痕'];

const mockHorses = () => {
  const mockPlayers: Player[] = Array.from({ length: 10 }, (_, i) => ({
    userid: `mock-${i}`,
    nickname: mockNicknames[i] || `玩家${i + 1}`,
    avatar: mockAvatars[i] || '',
    score: Math.floor(Math.random() * 60) + 10,
  }));
  updateHorses(mockPlayers);
};

watch(
  () => props.rankList,
  (players) => {
    console.log("[Rank1View] watch rankList 触发，players:", players?.length, JSON.stringify(players?.slice(0, 2)));
    if (players && players.length > 0) {
      updateHorses(players);
      // 按总分比例直接计算 boost（高分快、低分慢）
      recalculateBoostsFromScores(players);
    }
  },
  { immediate: true, deep: true },
);

// 进度百分比 → 屏幕像素位置
const horseTranslateX = (xPercent: number) => {
  return -120 + (xPercent / 100) * TOTAL_DISTANCE_PX;
};

// ========== 接收 H5 传来的 horseBoosts 数据（由 Game4.vue onAny 解析 WebSocket 提供） ==========
// 注意：加速计算已统一由 rankList watch → recalculateBoostsFromScores 处理
// horseBoosts prop 保留用于日后扩展（如直接传递 boost 值），当前不再单独 watch

// ========== 游戏主循环 (requestAnimationFrame 驱动位置 + 帧动画) ==========
let gameRafId: number | undefined;
let gameLastTs = 0;
let boostRecalcTimerMs = 0;
const BOOST_RECALC_INTERVAL_MS = 3000; // 每 3 秒用最新 rankList 重算 boost（防 WebSocket 断流导致 boost 过时）

const startGameLoop = () => {
  stopGameLoop();
  gameLastTs = 0;
  gameElapsedMs.value = 0;
  boostRecalcTimerMs = 0;

  const tick = (ts: number) => {
    if (!isGameRunning.value) {
      gameRafId = requestAnimationFrame(tick);
      return;
    }
    if (!gameLastTs) gameLastTs = ts;
    const dt = Math.min(ts - gameLastTs, 200);
    gameLastTs = ts;

    // 累计游戏运行时间（用于时间比例最小进度保障，参考 game2)
    gameElapsedMs.value += dt;
    const GAME_TOTAL_MS = 60_000; // 总游戏时间 60s
    const elapsedRatio = Math.min(gameElapsedMs.value / GAME_TOTAL_MS, 1);
    // 时间比例最小进度：确保即使无任何加速数据，马匹也会随倒计时推进
    const minProgress = elapsedRatio * MIN_PROGRESS_RATIO;

    // 每 3 秒用最新 rankList 重算 boost（兜底：防止 WebSocket 断流导致 boost 过时衰减至 0）
    boostRecalcTimerMs += dt;
    if (boostRecalcTimerMs >= BOOST_RECALC_INTERVAL_MS) {
      boostRecalcTimerMs = 0;
      recalculateBoostsFromScores(props.rankList);
    }

    const newTransientBoosts: Record<string, number> = {};
    const fixedBoosts = mockFixedBoosts.value; // mock 模式下的固定 boost（null = 非 mock）

    horses.value.forEach((horse) => {
      // 时间比例最小进度保障：马匹位置不低于 elapsedRatio * MIN_PROGRESS_RATIO%
      if (horse.xPercent < minProgress) {
        horse.xPercent = minProgress;
      }
      if (horse.xPercent >= 100) return;

      // mock 模式：使用固定 boost，不参与衰减；真实模式：使用 transientBoosts 并逐帧衰减
      const isMock = fixedBoosts && horse.id in fixedBoosts;
      const boost = isMock
        ? (fixedBoosts[horse.id] ?? 0)
        : (transientBoosts.value[horse.id] || 0);
      horse.boost = boost;

      horse.xPercent = Math.min(
        100,
        horse.xPercent +
          BASE_SPEED_PERCENT_PER_SEC * (1 + boost) * (dt / 1000),
      );

      horse.frameTimer += dt;
      const fc = horseFrameCount[horse.horseType] ?? 12;
      while (horse.frameTimer >= HORSE_FRAME_TICK_MS) {
        horse.frameTimer -= HORSE_FRAME_TICK_MS;
        horse.frameIndex = (horse.frameIndex + 1) % fc;
      }

      // mock 马匹 boost 不衰减，真实马匹正常衰减
      if (!isMock) {
        const decayed = boost * Math.pow(BOOST_DECAY, dt / (1000 / 60));
        if (decayed > 0.005) {
          newTransientBoosts[horse.id] = decayed;
        }
      }
    });

    transientBoosts.value = newTransientBoosts;
    gameRafId = requestAnimationFrame(tick);
  };

  gameRafId = requestAnimationFrame(tick);
};

const stopGameLoop = () => {
  if (gameRafId) {
    cancelAnimationFrame(gameRafId);
    gameRafId = undefined;
  }
};

// ========== 本地 mock 加速（每匹马分配不同的固定全程 boost，均匀分布 0~MAX_PULSE） ==========
let mockBoostTimer: ReturnType<typeof setInterval> | undefined;
const startMockBoost = () => {
  stopMockBoost();
  const totalHorses = horses.value.length;
  const fixedBoosts: Record<string, number> = {};

  // 按索引均匀分配 boost：第一批 (i=0) boost=0 不加速，最后一批 (i=n-1) boost=MAX_PULSE 满加速
  // 满加速马 60s 刚好到 100%，便于观察不同 boost 等级对应的终点位置
  horses.value.forEach((horse, i) => {
    fixedBoosts[horse.id] =
      totalHorses <= 1
        ? MAX_PULSE / 2
        : parseFloat(((i / (totalHorses - 1)) * MAX_PULSE).toFixed(2));
  });
  mockFixedBoosts.value = fixedBoosts;

  console.log(
    '[Rank1View] 🎯 固定 mock boost 分配（0 ~ MAX_PULSE 均匀分布）：',
    horses.value.map(h => `${h.nickname}: boost=${fixedBoosts[h.id]?.toFixed(2)} → 60s 预计进度=${(BASE_SPEED_PERCENT_PER_SEC * (1 + (fixedBoosts[h.id] ?? 0)) * 60).toFixed(0)}%`).join('\n  '),
  );
};
const stopMockBoost = () => {
  mockFixedBoosts.value = null;
  if (mockBoostTimer) {
    clearInterval(mockBoostTimer);
    mockBoostTimer = undefined;
  }
};

const computeFinalRank = (): RankItem[] => {
  // 从 WebSocket rankList 中取有效玩家（不排序，直接使用 WebSocket 返回的顺序）
  const valid = (props.rankList || []).filter(
    (p) => p.nickname !== "虚位以待" && !(p.wechat_id || "").startsWith("empty-"),
  );

  if (valid.length > 0) {
    // 直接使用 WebSocket 返回的顺序，不进行排序
    return valid.map((p, i) => ({
      rank: i + 1,
      userid: p.userid || p.wechat_id || `unknown-${i}`,
      nickname: p.nickname,
      avatar: p.avatar || "",
      score: Number(p.score ?? 0),
    }));
  }

  // 无 WebSocket 数据时降级：按 xPercent 降序（本地模拟模式）
  return horses.value
    .slice()
    .sort((a, b) => b.xPercent - a.xPercent)
    .map((h, i) => ({
      rank: i + 1,
      userid: h.id,
      nickname: h.nickname,
      avatar: h.avatar,
      score: Math.round(h.xPercent * 10),
    }));
};

const stopGame = () => {
  isGameRunning.value = false;
  stopGameLoop();
  stopMockBoost();

  // 播放喝彩音效

  // 计算最终排名
  finalRankList.value = computeFinalRank();

  // 打印排名数据到控制台
  console.log("========== 游戏结束 - 最终排名 ==========");
  console.table(
    finalRankList.value.map((item) => ({
      名次: item.rank,
      用户ID: item.userid,
      昵称: item.nickname,
      分数: item.score,
    })),
  );
  console.log("原始排名数据:", JSON.parse(JSON.stringify(finalRankList.value)));
};

const showFinalResult = () => {
  showResult.value = true;
  playApplauseMusic();
  finalRankList.value = computeFinalRank();
};

const startIntro = async () => {
  console.log("[Rank1View] startIntro 开始，当前 rankList:", props.rankList?.length, JSON.stringify(props.rankList?.slice(0, 2)));
  console.log("[Rank1View] 当前 horses 数量:", horses.value.length);
  
  // // 本地模拟已关闭，如需开启请取消以下注释
  // if ($is_local_mode()) {
  //   mockHorses();
  // }
  showResult.value = false;
  finalRankList.value = [];
  gameStarted.value = false;
  isGameRunning.value = false;
  stopApplauseMusic();
  transientBoosts.value = {};
  mockFixedBoosts.value = null;

  const countdownPromise = designStage.value?.startCountdown(3, 60);
  await new Promise((r) => setTimeout(r, 3500));

  console.log("[Rank1View] 倒计时结束，准备启动游戏，当前 horses:", horses.value.length, horses.value.map(h => h.nickname));
  
  gameStarted.value = true;
  isGameRunning.value = true;
  
  // 本地模拟已关闭，如需开启请取消以下注释
  // if (horses.value.length === 0) {
  //   const count = 8 + Math.floor(Math.random() * 3);
  //   const mockPlayers: Player[] = Array.from({ length: count }, (_, i) => ({
  //     userid: `auto-${i}`,
  //     nickname: mockNicknames[i] || `马匹${i + 1}`,
  //     avatar: mockAvatars[i] || '',
  //     score: Math.floor(Math.random() * 60) + 10,
  //   }));
  //   updateHorses(mockPlayers);
  //   console.log('[game4 Rank1View] 生成', count, '匹默认马');
  // }
  
  startGameLoop();
  // if ($is_local_mode()) {
  //   startMockBoost();
  // }

  await countdownPromise;
  stopGame();
};

const horseAvatarStyle = (horse: Horse) => {
  if (!horse.avatar) return {};
  return { backgroundImage: `url(${horse.avatar})`, backgroundSize: "cover" };
};

const preloadHorseFrames = () => {
  for (const frames of Object.values(horseFrames)) {
    for (const url of frames) {
      const img = new Image();
      img.src = url;
    }
  }
};

// 结果弹窗头像渲染（参考 game1 Rank2View）
const renderAvatar = (item: any) => {
  if (item && item.avatar) {
    return `background: url('${item.avatar}') center / cover no-repeat;`;
  }
  // 无头像时用 default-avator 占位（白底 + 居中 cover）
  return `background: #fff url('${defaultAvatarUrl}') center / cover no-repeat;`;
};

// 获取 podium 上三名选手（不足补空）
const podiumPlayers = (): RankItem[] => {
  const result = fullRankList.value.slice(0, 3);
  // 按 podium 视觉顺序：2 1 3（第二名在左，第三名在右）
  return [result[1]!, result[0]!, result[2]!];
};

onMounted(() => {
  preloadHorseFrames();
  // 本地模式：Game4.vue onMounted 会调用 startIntro() 来控制完整流程
  // 此处不自动开始，避免与 startIntro 冲突
});

onUnmounted(() => {
  // 仅清理游戏资源，不操作音乐（音乐由 Game4.vue 统一管理）
  // 注意：不能调 stopApplauseMusic()，因为 backgroundMusic 是全局共享的，
  // 组件卸载时 Game4.vue 的 watch 可能已将其切换为 BGM，pause 会误伤 BGM
  isGameRunning.value = false;
  stopGameLoop();
  stopMockBoost();
});

defineExpose({
  startIntro,
  showFinalResult,
});
</script>

<template>
  <DesignStage ref="designStage">
    <div class="screen-container" :class="{ paused: !gameStarted || !isGameRunning || showResult }">
      <div class="img-logo"></div>
      <div class="img-title-bg"></div>
      <div class="img-big-brum"></div>
      <div class="bg-top">
        <div class="bg-top-inner"></div>
        <div class="bg-top-inner"></div>
      </div>
      <div class="bg-bottom">
        <div class="bg-bottom-inner"></div>
        <div class="bg-bottom-inner"></div>
      </div>
      <!-- 倒计时结束后才显示马匹 -->
      <template v-if="gameStarted">
        <div
          v-for="horse in horses"
          :key="horse.id"
          class="horse-wrapper"
          :style="{
            bottom: `${horse.startY}px`,
            transform: `translateX(${horseTranslateX(horse.xPercent)}px)`,
          }"
        >
          <div class="horse-sprite">
            <img
              v-for="(url, frameIdx) in horseFrames[horse.horseType]"
              :key="frameIdx"
              :src="url"
              class="horse-frame"
              :class="{ active: frameIdx === horse.frameIndex }"
              alt=""
            />
          </div>
          <div class="horse-shadow"></div>
          <div class="horse-username">
            <span class="username-text">{{ horse.nickname }}</span>
          </div>
          <div class="horse-avatar" :style="horseAvatarStyle(horse)"></div>
        </div>
      </template>
      <div v-if="showResult" class="result-overlay">
        <div class="result-mask"></div>

        <!-- 领奖台 podium（参考 game1 Rank2View） -->
        <div class="podium">
          <div
            v-for="(item, idx) in podiumPlayers()"
            :key="item.userid || `podium-${idx}`"
            :class="['rank-no', `rank-no${idx === 1 ? 1 : idx === 0 ? 3 : 2}`]"
          >
            <div class="gu-burst"></div>
            <div class="avatar" :style="renderAvatar(item)"></div>
            <div class="nickname">{{ item.nickname }}</div>
            <div class="guan"></div>
            <!-- <div class="pai"></div> -->
          </div>
        </div>

        <!-- 第4-10名 rank-container -->
        <div class="rank-container">
          <div
            v-for="(item, index) in fullRankList.slice(3, 10)"
            :key="item.userid || `rank-${index}`"
          >
            <div class="no-icon">{{ index + 4 }}</div>
            <div>
              <div class="img-avatar-container">
                <div class="img-avatar" :style="renderAvatar(item)"></div>
              </div>
              <div class="txt-nickname">{{ item.nickname }}</div>
            </div>
          </div>
        </div>

        <div class="btn-next" @click="emit('next')"></div>
        <div class="btn-back" @click="emit('back')"></div>
      </div>
    </div>
  </DesignStage>
</template>

<style scoped>
.screen-container {
  width: 1920px;
  height: 1080px;
  position: relative;
  overflow: hidden;
}

.img-logo {
  background: v-bind("imageUrls.logo");
  background-size: cover;
  width: 428px;
  height: 77px;
  position: absolute;
  left: 37px;
  top: 82px;
  z-index: 20;
}

.img-title-bg {
  background: v-bind("imageUrls.titleBg");
  background-size: cover;
  width: 743px;
  height: 164.2px;
  position: absolute;
  left: 50%;
  top: 16px;
  transform: translateX(-50%);
  z-index: 20;
}

.img-big-brum {
  background: v-bind("imageUrls.bigBrum");
  background-size: cover;
  width: 161px;
  height: 150px;
  position: absolute;
  right: 59px;
  top: 392px;
  z-index: 2;
}

.screen-container.paused .bg-top,
.screen-container.paused .bg-bottom,
.screen-container.paused .horse {
  animation-play-state: paused;
}

.bg-top {
  width: 7680px;
  height: 1080px;
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  animation: bg-scroll-left 22s linear infinite;
  z-index: 1;
}

.bg-top-inner {
  width: 3840px;
  height: 1080px;
  background: v-bind("imageUrls.bgTop") 0 0 / 3840px 1080px
    no-repeat;
  flex-shrink: 0;
}

.bg-bottom {
  width: 7680px;
  height: 577px;
  position: absolute;
  bottom: 0;
  left: 0;
  display: flex;
  animation: bg-scroll-left 22s linear infinite;
  z-index: 2;
}

.bg-bottom-inner {
  width: 3840px;
  height: 577px;
  background: v-bind("imageUrls.bgBottom") 0 0 / 3840px 577px
    no-repeat;
  flex-shrink: 0;
}

.horse-wrapper {
  position: absolute;
  left: 0;
  width: 280px;
  height: 280px;
  transition: transform 0.2s linear;
  will-change: transform;
  z-index: 10;
}

.horse-sprite {
  position: relative;
  width: 280px;
  height: 280px;
}

.horse-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;
  pointer-events: none;
  z-index: 1;
}

.horse-frame.active {
  opacity: 1;
}

.horse-shadow {
  position: absolute;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%);
  width: 180px;
  height: 24px;
  background: radial-gradient(ellipse, rgba(0, 0, 0, 0.45) 0%, transparent 70%);
  border-radius: 50%;
  pointer-events: none;
  z-index: 0;
}

.horse-username {
  background: v-bind("imageUrls.username");
  background-size: contain;
  background-repeat: no-repeat;
  width: 120px;
  height: 44px;
  position: absolute;
  top: 80px;
  left: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

.username-text {
  position: absolute;
  top: 2px;
  color: #000;
  font-size: 16px;
  font-weight: bold;
  max-width: 100px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding-left: 6px;
  box-sizing: border-box;
}

.horse-avatar {
  background: v-bind("imageUrls.avatar");
  background-size: cover;
  width: 50px;
  height: 50px;
  position: absolute;
  top: 80px;
  left: 60px;
  border-radius: 50%;
  border: 2px solid #FFCF44;
  z-index: 3;
}

@keyframes bg-scroll-left {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-3840px);
  }
}


/* ========== 结果弹窗 ========== */
.result-overlay {
  width: 1920px;
  height: 1080px;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.result-mask {
  width: 1920px;
  height: 1080px;
  position: absolute;
  top: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.5);
  z-index: 0;
}

/* ========== podium 领奖台 ========== */
.podium {
  background: v-bind("imageUrls.podium") no-repeat center;
  width: 1347px;
  height: 412px;
  position: absolute;
  top: 294px;
  left: 287px;
  z-index: 1;
}

.gu-burst {
  width: 200px;
  height: 200px;
  position: absolute;
  z-index: 1;
  border-radius: 50%;
  opacity: 1;
  transform: scale(0.6);
  transform-origin: center center;
  background: v-bind("imageUrls.fireworks") center / cover no-repeat;
  pointer-events: none;
  animation: gu-burst-expand 1.2s ease-out infinite;
}

@keyframes gu-burst-expand {
  0% {
    opacity: 1;
    transform: scale(0.6);
  }
  100% {
    opacity: 0;
    transform: scale(1);
  }
}

.rank-no {
  position: relative;
}

/* 第1名 (中间) */
.rank-no1 {
  .gu-burst { left: 605px; top: -235px; }
  .avatar {
    width: 120px; height: 120px; border-radius: 60px;
    position: absolute; left: 610px; top: -141px;
  }
  .nickname {
    width: 167px; height: 46px;
    background: #FFCF44; color: white;
    text-align: center; line-height: 46px;
    position: absolute; left: 590px; top: -32px;
    z-index: 1; border-radius: 23px;
  }
  .guan {
    background: v-bind("imageUrls.guan1");
    width: 64px; height: 64px;
    position: absolute; top: -160px; left: 581px;
  }
  .pai {
    background: v-bind("imageUrls.pai1");
    width: 212px; height: 200px;
    position: absolute; left: 570px; top: 40px;
  }
}

/* 第2名 */
.rank-no2 {
  .gu-burst { left: 908px; top: -81px; }
  .avatar {
    width: 120px; height: 120px; border-radius: 60px;
    position: absolute; left: 920px; top: 25px;
  }
  .nickname {
    width: 167px; height: 46px;
    background: #CA9600; color: white;
    text-align: center; line-height: 46px;
    position: absolute; left: 897px; top: 136px;
    z-index: 1; border-radius: 23px;
  }
  .guan {
    background: v-bind("imageUrls.guan3") no-repeat center;
    width: 96px; height: 96px;
    position: absolute; left: 877px; top: -14px;
  }
  .pai {
    background: v-bind("imageUrls.pai3") no-repeat center;
    width: 212px; height: 200px;
    position: absolute; right: 130px; top: 50px;
  }
}

/* 第3名 */
.rank-no3 {
  .gu-burst { left: 318px; top: -120px; }
  .avatar {
    width: 120px; height: 120px; border-radius: 60px;
    position: absolute; left: 333px; top: -17px;
  }
  .nickname {
    width: 167px; height: 46px;
    background: #E2E2E2; color: #AFAFAF;
    text-align: center; line-height: 46px;
    position: absolute; top: 95px;left: 309px;
    z-index: 1; border-radius: 23px;
  }
  .guan {
    background: v-bind("imageUrls.guan2") no-repeat center;
    width: 96px; height: 96px;
    position: absolute; left: 289px; top: -54px;
  }
  .pai {
    background: v-bind("imageUrls.pai2") no-repeat center;
    width: 212px; height: 200px;
    position: absolute; left: 140px; top: 50px;
  }
}

/* ========== rank-container 第4-10名 ========== */
.rank-container {
  display: flex;
  align-items: center;
  width: 1270px;
  height: 115px;
  position: absolute;
  bottom: 243px;
  left: 325px;
  z-index: 1;
}

.rank-container > div {
  flex: 1;
  display: grid;
  width: 100px;
  height: 100%;
}

.rank-container .no-icon {
  background: v-bind("imageUrls.rankIcon") no-repeat center;
  width: 40px;
  height: 40px;
  position: absolute;
  text-align: center;
  line-height: 40px;
  color: white;
  font-weight: bold;
}

.rank-container .img-avatar-container {
  position: relative;
  margin: 0 auto;
  margin-top: 10px;
  width: 72px;
  height: 72px;
  border-radius: 36px;
}

.rank-container .img-avatar-container::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: v-bind("imageUrls.avatarAnimation");
  animation: avatar-rotate 10s linear infinite;
}

@keyframes avatar-rotate {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.rank-container .img-avatar {
  position: relative;
  top: 6px;
  z-index: 1;
  margin: 0 auto;
  width: 60px;
  height: 60px;
  border-radius: 30px;
  background: v-bind("imageUrls.avatar");
}

.rank-container .txt-nickname {
  color: white;
  font-size: 20px;
  text-align: center;
}

/* ========== btn-next ========== */
.btn-next {
  position: absolute;
  bottom: 50px;
  left: 620px;
  width: 316px;
  height: 105px;
  cursor: pointer;
  background: v-bind("imageUrls.next") center / cover no-repeat;
  z-index: 2;
}
.btn-back {
  position: absolute;
  bottom: 50px;
  left: 1020px;
  width: 316px;
  height: 105px;
  cursor: pointer;
  background: v-bind("imageUrls.back") center / cover no-repeat;
  z-index: 2;
}
</style>
