<script setup>
import { ref, onMounted, computed, onBeforeUnmount } from "vue";
import { onShow, onHide, onLoad, onShareAppMessage } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import PlayerSeats from "@/components/PlayerSeats.vue";
import GuideTwo from "@/components/GuideTwo.vue";
import SButton from "@/components/SButton.vue";
import Avatar from "@/components/Avatar.vue";
import ScreenHint from "@/components/ScreenHint.vue";
import ModalDialog from "@/components/ModalDialog.vue";
import {
  getRoomAPI,
  exitRoomAPI,
  chooseTeamAPI,
  getReadyAPI,
  kickPlayerAPI,
  getBattleAPI,
} from "@/apis";
import { debounce, isLimitError } from "@/util";
import { MESSAGETYPES, MESSAGETYPESV2 } from "@/constants";
import useStore from "@/store";
import { storeToRefs } from "pinia";
import audioManager from "@/audioManager";
import { returnToBattle } from "@/utils/matchReturn";
const store = useStore();
const { user } = storeToRefs(store);

const room = ref({});
const roomNumber = ref("");
const owner = ref({});
const opponent = ref({});
const players = ref([]);
const blueTeam = ref([]);
const redTeam = ref([]);

const isMember = (player = {}) => player.vip === true || player.sVip === true;

const getMemberNicknameClass = (player = {}) => [
  "member-nickname",
  player.vip === true && player.sVip !== true ? "member-nickname--vip" : "",
  player.sVip === true ? "member-nickname--svip" : "",
];

const normalizeRoomPlayer = (member = {}) => ({
  ...(member.userInfo || {}),
  vip: member.vip ?? member.userInfo?.vip,
  sVip: member.sVip ?? member.userInfo?.sVip,
});

/**
 * 根据对战类型和房间人数动态生成页面标题
 * battleType=1: 组队对战；count 2/4/6 分别对应 1v1/2v2/3v3
 * battleType=2: 多人乱斗
 */
const battleTitle = computed(() => {
  if (!room.value.battleType) return "好友约战";
  if (room.value.battleType === 2) return "多人乱斗";
  const half = room.value.count / 2;
  return `${half}v${half}对抗赛`;
});

/** 靶纸尺寸（cm），由 URL 参数或 API 返回的 targetType 字段填充 */
const targetSize = ref(0);

/**
 * 根据 targetSize 动态生成靶纸尺寸文本，如"40cm"
 * 数据未就绪时显示 "--"；数据来源：创建者取 URL 参数 target，加入者取 API 返回的 targetType
 */
const targetSizeLabel = computed(() =>
  targetSize.value ? `${targetSize.value}cm` : '--'
);

const ready = ref(false);
const allReady = ref(false);
const timer = ref(null);
const goBattle = ref(false);
const showLimitModal = ref(false);
const readySubmitting = ref(false);
const navigationPending = ref(false);
let pageMounted = false;
let pageVisible = false;
let foregroundGeneration = 0;
const MATCH_INFO_RETRY_DELAY_MS = 500;
/** 从结算页返回时为 true，跳过进场靶纸语音 */
const skipTargetAudio = ref(false);

const wait = (delay) =>
  new Promise((resolve) => {
    setTimeout(resolve, delay);
  });

const isCurrentForeground = (generation) =>
  pageMounted &&
  pageVisible &&
  generation === foregroundGeneration &&
  !navigationPending.value;

const redirectOnce = (url) =>
  new Promise((resolve, reject) => {
    if (navigationPending.value) {
      resolve(false);
      return;
    }

    navigationPending.value = true;
    uni.redirectTo({
      url,
      success: resolve,
      fail: (error) => {
        navigationPending.value = false;
        goBattle.value = false;
        reject(error);
      },
    });
  });

async function queryCurrentBattle(generation) {
  try {
    return await getBattleAPI();
  } catch (error) {
    await wait(MATCH_INFO_RETRY_DELAY_MS);
    if (!isCurrentForeground(generation)) throw error;
    return getBattleAPI();
  }
}

async function returnToCurrentBattle(battle) {
  if (!battle?.matchId || navigationPending.value) return false;

  goBattle.value = true;
  try {
    const returned = await returnToBattle(battle, redirectOnce);
    if (!returned) goBattle.value = false;
    return returned;
  } catch (error) {
    goBattle.value = false;
    throw error;
  }
}

async function reconcileBattleRoom(generation) {
  let battle = null;
  try {
    battle = await queryCurrentBattle(generation);
  } catch (error) {
    if (!isCurrentForeground(generation)) return;
    console.log("resume room match info error", error);
    uni.showToast({
      title: "比赛状态查询失败，请重试",
      icon: "none",
    });
    return;
  }

  if (!isCurrentForeground(generation)) return;
  if (battle?.matchId) {
    try {
      await returnToCurrentBattle(battle);
    } catch (error) {
      console.log("return to room battle error", error);
      uni.showToast({
        title: "进入比赛失败，请重试",
        icon: "none",
      });
    }
    return;
  }

  let roomStarted = false;
  try {
    roomStarted = await refreshRoomData();
  } catch (error) {
    if (isCurrentForeground(generation)) {
      console.log("refresh room data error", error);
    }
    return;
  }

  if (!isCurrentForeground(generation) || !roomStarted) return;

  await wait(MATCH_INFO_RETRY_DELAY_MS);
  if (!isCurrentForeground(generation)) return;

  try {
    battle = await queryCurrentBattle(generation);
  } catch (error) {
    if (!isCurrentForeground(generation)) return;
    console.log("retry room match info error", error);
    uni.showToast({
      title: "比赛状态查询失败，请重试",
      icon: "none",
    });
    return;
  }

  if (!isCurrentForeground(generation)) return;
  if (battle?.matchId) {
    try {
      await returnToCurrentBattle(battle);
    } catch (error) {
      console.log("return to room battle error", error);
      uni.showToast({
        title: "进入比赛失败，请重试",
        icon: "none",
      });
    }
    return;
  }

  uni.showToast({
    title: "比赛正在创建，请稍候",
    icon: "none",
  });
}

/**
 * 从服务端刷新当前房间数据，更新成员列表、准备状态等信息
 * 仅在 roomNumber 有效且房间未开始时执行
 */
async function refreshRoomData() {
  if (!roomNumber.value) return false;
  const result = await getRoomAPI(roomNumber.value);
  if (result.started) return true;
  room.value = result;
  // 加入者通过 API 返回的 targetType 字段同步靶纸尺寸，并持久化到本地缓存
  if (result.targetType) {
    targetSize.value = result.targetType;
    uni.setStorageSync(`targetSize_${roomNumber.value}`, result.targetType);
  } else if (targetSize.value === 0) {
    // API 无该字段时，从本地缓存兜底（如"返回房间"场景）
    const stored = uni.getStorageSync(`targetSize_${roomNumber.value}`);
    if (stored) targetSize.value = stored;
  }
  owner.value = {};
  opponent.value = {};
  const members = result.members || [];
  if (members.length === result.count) {
    allReady.value = members.every((m) => !!m.userInfo.state);
  }
  members.some((m) => {
    if (m.userInfo.id === user.value.id) {
      ready.value = !!m.userInfo.state;
      return true;
    }
    return false;
  });
  members.some((m) => {
    const player = normalizeRoomPlayer(m);
    if (player.id === result.creator) {
      owner.value = {
        id: player.id,
        name: player.name,
        avatar: player.avatar,
        rankLvl: player.rankLvl,
        vip: player.vip,
        sVip: player.sVip,
        ready: !!player.state,
      };
      return true;
    }
    return false;
  });
  if (result.battleType === 1 && result.count === 2) {
    result.members.forEach((m) => {
      const player = normalizeRoomPlayer(m);
      if (player.id !== owner.value.id) {
        opponent.value = {
          id: player.id,
          name: player.name,
          avatar: player.avatar,
          rankLvl: player.rankLvl,
          vip: player.vip,
          sVip: player.sVip,
          ready: !!player.state,
        };
      }
    });
  } else if (result.battleType === 2) {
    players.value = [];
    const ownerIndex = result.members.findIndex(
      (m) => m.userInfo.id === result.creator
    );
    if (ownerIndex !== -1) {
      players.value.push(normalizeRoomPlayer(result.members[ownerIndex]));
    } else {
      players.value.push({});
    }
    result.members.forEach((m, index) => {
      if (ownerIndex !== index) players.value.push(normalizeRoomPlayer(m));
    });
  } else {
    players.value = new Array(result.count).fill({});
    refreshMembers(result.members);
  }
  if (timer.value) clearInterval(timer.value);
  // timer.value = setTimeout(refreshRoomData, 2000);
  return false;
}

const getReady = debounce(async () => {
  if (readySubmitting.value) return;
  readySubmitting.value = true;
  try {
    await getReadyAPI(roomNumber.value);
    ready.value = true;
  } catch (error) {
    if (isLimitError(error)) {
      showLimitModal.value = true;
      return;
    }
    console.log("room ready error", error);
  } finally {
    readySubmitting.value = false;
  }
});

const closeLimitModal = () => {
  showLimitModal.value = false;
};

const goVipPage = () => {
  showLimitModal.value = false;
  uni.navigateTo({
    url: "/pages/member/be-vip",
  });
};

const refreshMembers = (members = []) => {
  blueTeam.value = [];
  redTeam.value = [];
  members.forEach((m, index) => {
    const player = { ...normalizeRoomPlayer(m), groupType: m.groupType };
    players.value[index] = player;
    if (m.groupType === 1) {
      blueTeam.value.push({ ...player, groupType: 1 });
    } else if (m.groupType === 2) {
      redTeam.value.push({ ...player, groupType: 2 });
    }
  });
  for (let i = 0; i < room.value.count / 2; i++) {
    if (!blueTeam.value[i]) blueTeam.value[i] = {};
    if (!redTeam.value[i]) redTeam.value[i] = {};
  }
};

async function onReceiveMessage(message) {
  if (Array.isArray(message)) {
    message.forEach((msg) => {
      if (msg.roomNumber !== roomNumber.value) return;
      if (msg.constructor === MESSAGETYPES.UserEnterRoom) {
        refreshRoomData();
      } else if (msg.constructor === MESSAGETYPES.UserExitRoom) {
        if (msg.userId === user.value.id) {
          uni.showToast({
            title: "你被踢出房间",
            icon: "none",
          });
          setTimeout(() => {
            uni.navigateBack();
          }, 1000);
        } else {
          refreshRoomData();
        }
      } else if (msg.constructor === MESSAGETYPES.TeamUpdate) {
        refreshRoomData();
      } else if (msg.constructor === MESSAGETYPES.SomeoneIsReady) {
        refreshRoomData();
      } else if (msg.constructor === MESSAGETYPES.RoomDestroy) {
        uni.showToast({
          title: "房间已解散",
          icon: "none",
        });
        setTimeout(() => {
          uni.navigateBack();
        }, 1000);
      }
    });
  } else if (message.type === MESSAGETYPESV2.AboutToStart) {
    if (navigationPending.value) return;
    const matchId = message.matchId || message.id;
    if (!matchId) return;
    goBattle.value = true;
    let url = "";
    if (message.mode <= 3) {
      uni.setStorageSync("blue-team", message.teams[1].players || []);
      uni.setStorageSync("red-team", message.teams[2].players || []);
      url = "/pages/team-battle/index?battleId=" + matchId;
    } else {
      url = "/pages/melee-battle?battleId=" + matchId;
    }
    try {
      await redirectOnce(url);
    } catch (error) {
      console.log("redirect to room battle error", error);
    }
  }
}

const chooseTeam = async (team) => {
  const result = await chooseTeamAPI(roomNumber.value, team);
  refreshMembers(result.members);
};

/** 待确认踢出的玩家信息 */
const playerToKick = ref(null);
/** 控制踢出确认弹窗的显示状态 */
const showKickConfirm = ref(false);

/**
 * 点击踢出按钮，弹出二次确认弹窗
 * @param {object} player - 被踢的玩家信息
 */
const removePlayer = (player) => {
  playerToKick.value = player;
  showKickConfirm.value = true;
};

/** 确认踢出：调用 API 并关闭弹窗 */
const confirmKick = async () => {
  if (!playerToKick.value) return;
  await kickPlayerAPI(roomNumber.value, playerToKick.value.id);
  showKickConfirm.value = false;
  playerToKick.value = null;
};

/** 取消踢出：关闭弹窗 */
const cancelKick = () => {
  showKickConfirm.value = false;
  playerToKick.value = null;
};

const canClick = computed(() => {
  if (ready.value) return false;
  const { members = [] } = room.value;
  if (members.length < 2) return false;
  if (
    owner.value.id === user.value.id &&
    members.some((m) => !m.userInfo.state && m.userInfo.id !== owner.value.id)
  )
    return false;
  return true;
});

/**
 * 根据对战类型和人数动态生成分享文案
 * 1v1 / 默认 → "星球论箭，来一决高下敢否?"
 * 2v2 → "2v2对抗赛，是兄弟来助我一把!"
 * 3v3 → "3v3对抗赛，来了马上发车!"
 * 乱斗 → "热血乱斗赛，敢来争锋?"
 */
const shareTitle = computed(() => {
  const { battleType, count } = room.value;
  if (battleType === 2) return '热血乱斗赛，敢来争锋?';
  if (battleType === 1 && count === 4) return '2v2对抗赛，是兄弟来助我一把!';
  if (battleType === 1 && count === 6) return '3v3对抗赛，来了马上发车!';
  return '星球论箭，来一决高下敢否?';
});

/**
 * 根据对战类型和靶纸尺寸动态返回分享封面图路径，共 4 张图：
 *   contest_share_20.png — 约战/对抗赛 + 20cm 靶
 *   contest_share_40.png — 约战/对抗赛 + 40cm 靶
 *   melee_share_20.png   — 多人乱斗 + 20cm 靶
 *   melee_share_40.png   — 多人乱斗 + 40cm 靶
 *
 * 当 targetSize 未知时默认取 20cm 图。
 */
const shareImage = computed(() => {
  const type = room.value.battleType === 2 ? 'melee' : 'contest';
  const size = targetSize.value === 40 ? '40' : '20';
  return `https://static.shelingxingqiu.com/shootmini/static/share/${type}_share_${size}.png`;
});

onShareAppMessage(() => {
  return {
    title: shareTitle.value,
    path: "/pages/friend-battle?roomID=" + roomNumber.value,
    imageUrl: shareImage.value,
  };
});

/**
 * onShow 生命周期：页面显示时刷新房间数据
 * 注：uni-app 中 onShow 可能早于 onLoad 执行，此时 roomNumber 尚未赋值，
 * refreshRoomData 会提前 return。
 */
onShow(() => {
  goBattle.value = false;
  navigationPending.value = false;
  pageVisible = true;
  const generation = ++foregroundGeneration;
  if (pageMounted) void reconcileBattleRoom(generation);
});

onHide(() => {
  pageVisible = false;
  foregroundGeneration += 1;
});

/**
 * 页面加载时解析路由参数，初始化房间号
 * - 存入本地 ref（供页面内部逻辑使用）
 * - 同步到 Pinia Store（供 Header 组件展示房号胶囊）
 */
onLoad(async (options) => {
  // 从结算页跳回时携带 fromResult=1，标记跳过进场语音
  if (options.fromResult) skipTargetAudio.value = true;
  if (options.roomNumber) {
    roomNumber.value = options.roomNumber;
    store.updateRoomNumber(options.roomNumber);
  }
  // 创建者通过 URL 参数 target（1→20cm，2→40cm）初始化靶纸尺寸，并持久化到本地缓存
  if (options.target) {
    targetSize.value = parseInt(options.target) * 20;
    uni.setStorageSync(`targetSize_${roomNumber.value}`, targetSize.value);
  } else if (roomNumber.value) {
    // "返回房间"等无 target 参数的场景：从本地缓存恢复（待 refreshRoomData 进一步覆盖）
    const stored = uni.getStorageSync(`targetSize_${roomNumber.value}`);
    if (stored) targetSize.value = stored;
  }
  if (pageMounted && pageVisible) {
    const generation = ++foregroundGeneration;
    void reconcileBattleRoom(generation);
  }
});

/**
 * 组件挂载后：保持屏幕常亮、注册 WebSocket 消息监听
 * 房间号已通过 onLoad 同步到 Store，Header 从 Store 直接读取，无需额外通知
 */
onMounted(() => {
  uni.setKeepScreenOn({
    keepScreenOn: true,
  });
  uni.$on("socket-inbox", onReceiveMessage);
  pageMounted = true;
  if (pageVisible) void reconcileBattleRoom(foregroundGeneration);
  // 页面加载完成 1 秒后根据靶纸尺寸播报对应语音；从结算页返回时跳过
  setTimeout(() => {
    if (!skipTargetAudio.value) {
      const key = targetSize.value === 40 ? '40CM全环靶' : '20CM全环靶';
      audioManager.play(key);
    }
  }, 1000);
});

onBeforeUnmount(() => {
  pageMounted = false;
  pageVisible = false;
  foregroundGeneration += 1;
  uni.setKeepScreenOn({
    keepScreenOn: false,
  });
  uni.$off("socket-inbox", onReceiveMessage);
  if (!goBattle.value) exitRoomAPI(roomNumber.value);
  if (timer.value) clearInterval(timer.value);
  timer.value = null;
});
</script>

<template>
  <Container :title="battleTitle">
    <view class="standby-phase">
      <GuideTwo>
        <view class="battle-guide">
          <view class="guide-tips">
            <text class="guide-tips__target">请使用{{ targetSizeLabel }}全环靶</text>
            <text class="guide-tips__warn">如果实际靶纸与选择靶纸不同，将导致射箭无效</text>
          </view>
        </view>
      </GuideTwo>
      <view v-if="room.battleType === 1 && room.count === 2" class="team-mode">
        <image src="https://static.shelingxingqiu.com/attachment/2025-08-05/dbua9nuf5fyeph7cxi.png" mode="widthFix" />
        <view>
          <view v-if="owner.id" class="player" :style="{ transform: 'translateY(-60px)' }">
            <Avatar :src="owner.avatar" :size="60" />
            <text>管理员</text>
            <view
              v-if="isMember(owner)"
              :class="['room-player-name', ...getMemberNicknameClass(owner)]"
            >
              <text class="member-nickname__text">{{ owner.name }}</text>
              <text v-if="owner.sVip === true" class="member-nickname__shine">
                {{ owner.name }}
              </text>
            </view>
            <text v-else class="room-player-name">{{ owner.name }}</text>
          </view>
          <view v-else class="no-player" :style="{ transform: 'translateY(-60px)' }">
            <image src="../static/question-mark.png" mode="widthFix" />
          </view>
          <image src="https://static.shelingxingqiu.com/shootmini/static/versus.png" mode="widthFix" />
          <view v-if="opponent.id" class="player" :style="{ transform: 'translateY(60px)' }">
            <Avatar :src="opponent.avatar" :size="60" />
            <text class="ready" :style="{ opacity: opponent.ready ? 1 : 0 }">
              已准备
            </text>
            <view
              v-if="isMember(opponent)"
              :class="['room-player-name', ...getMemberNicknameClass(opponent)]"
            >
              <text class="member-nickname__text">{{ opponent.name }}</text>
              <text v-if="opponent.sVip === true" class="member-nickname__shine">
                {{ opponent.name }}
              </text>
            </view>
            <text v-else class="room-player-name">{{ opponent.name }}</text>
            <button v-if="owner.id === user.id" hover-class="none" class="remove-player"
              @click="() => removePlayer(opponent)">
              <image src="../static/close-white.png" mode="widthFix" />
            </button>
          </view>
          <view class="no-player" v-else>
            <image src="../static/question-mark.png" mode="widthFix" />
          </view>
        </view>
      </view>
      <block v-if="room.battleType === 1 && room.count >= 4">
        <view class="all-players">
          <image src="https://static.shelingxingqiu.com/attachment/2025-08-13/dc0x1p59iab6cvbhqc.png" mode="widthFix" />
          <image v-if="room.count === 4" src="https://static.shelingxingqiu.com/shootmini/static/title-2v2.png" mode="widthFix" />
          <image v-if="room.count === 6" src="https://static.shelingxingqiu.com/shootmini/static/title-3v3.png" mode="widthFix" />
          <view>
            <view v-for="(item, index) in players" :key="index">
              <Avatar v-if="item.id" :src="item.avatar" :size="36" />
              <text v-if="owner.id === item.id">管理员</text>
              <!-- 仅房主可见踢人按钮，且不能踢自己 -->
              <button v-if="owner.id !== item.id && item.id && owner.id === user.id" hover-class="none" class="remove-player"
                @click="() => removePlayer(item)" :style="{ top: '-10rpx', right: '-10rpx' }">
                <image src="../static/close-white.png" mode="widthFix" />
              </button>
            </view>
          </view>
        </view>
        <view class="choose-side">
          <view>
            <view v-for="(item, index) in redTeam" :key="index" class="choose-side-left-item">
              <button hover-class="none" v-if="item.id === user.id" @click="chooseTeam(0)">
                <image src="../static/close-grey.png" mode="widthFix" />
              </button>
              <view
                v-if="item.id && isMember(item)"
                :class="['team-player-name', 'truncate', ...getMemberNicknameClass(item)]"
              >
                <text class="member-nickname__text">{{ item.name }}</text>
                <text v-if="item.sVip === true" class="member-nickname__shine">
                  {{ item.name }}
                </text>
              </view>
              <text v-else class="truncate">{{ item.name || "我要加入" }}</text>
              <view v-if="item.id" class="team-player-avatar">
                <Avatar :src="item.avatar" :size="36" />
                <text :style="{ opacity: !!item.state ? 1 : 0 }">已准备</text>
              </view>
              <button v-else hover-class="none" @click="chooseTeam(2)">
                <image src="../static/add-grey.png" mode="widthFix" />
              </button>
            </view>
          </view>
          <view>
            <view v-for="(item, index) in blueTeam" :key="index" class="choose-side-right-item">
              <view v-if="item.id" class="team-player-avatar">
                <Avatar :src="item.avatar" :size="36" />
                <text :style="{ opacity: !!item.state ? 1 : 0 }">已准备</text>
              </view>
              <button v-else hover-class="none" @click="chooseTeam(1)">
                <image src="../static/add-grey.png" mode="widthFix" />
              </button>
              <view
                v-if="item.id && isMember(item)"
                :class="['team-player-name', 'truncate', ...getMemberNicknameClass(item)]"
              >
                <text class="member-nickname__text">{{ item.name }}</text>
                <text v-if="item.sVip === true" class="member-nickname__shine">
                  {{ item.name }}
                </text>
              </view>
              <text v-else class="truncate">{{ item.name || "我要加入" }}</text>
              <button hover-class="none" v-if="item.id === user.id" @click="chooseTeam(0)">
                <image src="../static/close-grey.png" mode="widthFix" />
              </button>
            </view>
          </view>
        </view>
      </block>
      <!-- isOwner：当前用户是房主时才展示踢人按钮 -->
      <PlayerSeats v-if="room.battleType === 2" :total="room.count || 10" :players="players"
        :removePlayer="removePlayer" :isOwner="owner.id === user.id" />
      <view>
        <SButton
          :disabled="!canClick || readySubmitting"
          :onClick="() => { $clickSound(); return getReady(); }"
        >
          {{
            allReady.value
              ? "即将进入对局..."
              : owner.id === user.id
                ? "开始对局"
                : "我准备好了"
          }}
        </SButton>
        <text class="tips">所有人准备好后由房主点击开始</text>
      </view>
    </view>
  </Container>
  <ModalDialog
    :show="showLimitModal"
    :content="'今日约战次数已经用完\n开通会员可增加次数'"
    cancelText="知道了"
    confirmText="去开通"
    :onCancel="closeLimitModal"
    :onConfirm="goVipPage"
  />
  <!-- 踢出玩家二次确认弹窗（不传 onClose，屏蔽 X 关闭按钮） -->
  <ScreenHint :show="showKickConfirm">
    <view class="kick-confirm">
      <!-- 弹窗标题，玩家名字高亮显示 -->
      <text class="kick-confirm__title">
        是否把「<text style="color: #F7D550">{{ playerToKick && playerToKick.name }}</text>」移出房间？
      </text>
      <!-- 按钮区：确认在左，取消在右 -->
      <view class="kick-confirm__btns">
        <button hover-class="none" class="kick-confirm__btn kick-confirm__btn--confirm" @click="confirmKick">确定</button>
        <button hover-class="none" class="kick-confirm__btn kick-confirm__btn--cancel" @click="cancelKick">取消</button>
      </view>
    </view>
  </ScreenHint>
</template>

<style scoped>
.standby-phase {
  width: 100%;
  height: calc(100% - 40px);
  overflow-x: hidden;
}

.tips {
  color: #fff9;
  width: 100%;
  text-align: center;
  display: block;
  margin-top: 10px;
  font-size: 12px;
}

.player-unknow {
  width: 40px;
  height: 40px;
  margin: 0 10px;
  border: 1px solid #fff3;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: #69686866;
}

.player-unknow>image {
  width: 40%;
}

.team-mode {
  width: calc(100vw - 30px);
  height: 125vw;
  margin: 0 15px 15px 15px;
}

.team-mode>image:first-child {
  position: absolute;
  width: calc(100vw - 30px);
  z-index: -1;
}

.team-mode>view {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 95%;
}

.player {
  width: 70px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  transform: translateY(-60px);
  color: #fff;
  font-size: 14px;
  position: relative;
}

.player>image {
  width: 70px;
  height: 70px;
  border-radius: 50%;
  background-color: #ccc;
  margin-bottom: 5px;
}

.player>text:nth-child(2) {
  color: #000;
  background-color: #fed847;
  font-size: 16rpx;
  border-radius: 20rpx;
  line-height: 26rpx;
  padding: 0 10rpx;
  margin-top: -16rpx;
  position: relative;
}

.room-player-name {
  margin-top: 6rpx;
}

.player>text,
.room-player-name {
  max-width: 100px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}

.room-player-name .member-nickname__text,
.room-player-name .member-nickname__shine {
  font-size: 14px;
  text-align: center;
}

.player .ready {
  background-color: #2c261fb3 !important;
  border: 1rpx solid #a3793f66 !important;
  color: #fed847 !important;
}

/* 踢出确认弹窗内容 */
.kick-confirm {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 20rpx 30rpx;
  color: #fff;
}
.kick-confirm__title {
  font-size: 30rpx;
  font-weight: 500;
  text-align: center;
  line-height: 1.5;
  /* 标题与按钮区间距 */
  margin-bottom: 58rpx;
}
.kick-confirm__btns {
  display: flex;
  /* 两个按钮间距 */
  gap: 16rpx;
}
/* 按钮公共基础样式：固定宽高与圆角 */
.kick-confirm__btn {
  font-size: 28rpx;
  width: 232rpx;
  height: 70rpx;
  border-radius: 44rpx;
  line-height: 70rpx;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* 取消按钮：白色半透明背景（用 rgba 避免 opacity 平铺到文字） */
.kick-confirm__btn--cancel {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: #FFFFFF;
  font-weight: 500;
  font-size: 28rpx;
  text-align: center;
  border-radius: 44rpx;
}
.kick-confirm__btn--cancel::after {
  border: none;
}
/* 确认按钮：黄色实心背景 */
.kick-confirm__btn--confirm {
  background: #FED847;
  border: none;
  color: #000000;
  font-weight: 500;
  font-size: 28rpx;
  text-align: center;
  border-radius: 44rpx;
}
.kick-confirm__btn--confirm::after {
  border: none;
}

.remove-player {
  width: 40rpx;
  height: 40rpx;
  border-radius: 50%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: linear-gradient(0deg, #996c29b8 0%, #201e1aaf 100%);
  position: absolute;
  top: 0;
  right: 0;
}

.remove-player>image {
  width: 90%;
  height: 90%;
}

.team-mode>view>image:nth-child(2) {
  width: 120px;
}

.no-player {
  width: 70px;
  height: 70px;
  border-radius: 50%;
  background-color: #ccc;
  display: flex;
  justify-content: center;
  align-items: center;
  transform: translateY(60px);
}

.no-player>image {
  width: 20px;
  margin-right: 2px;
}

.btns {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.battle-guide {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.battle-guide>button:last-child {
  color: #fed847;
  border: 1px solid #fed847;
  margin-right: 10px;
  padding: 5px 12px;
  border-radius: 20px;
  position: relative;
  font-size: 28rpx;
}

.all-players {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  height: 83vw;
}

.all-players>image:first-child {
  position: absolute;
  width: 100%;
}

.all-players>image:nth-child(2) {
  width: 25vw;
  position: relative;
}

.all-players>view {
  position: relative;
  width: 42vw;
  height: 42vw;
  margin-top: 7vw;
}

.all-players>view>view {
  position: absolute;
  left: 50%;
  top: 50%;
}

/* 4个头像 - 正方形排列 */
.all-players>view>view:nth-child(1):nth-last-child(4) {
  transform: translate(-50%, -50%) rotate(-30deg) translateY(-21.5vw) rotate(30deg);
}

.all-players>view>view:nth-child(2):nth-last-child(3) {
  transform: translate(-50%, -50%) rotate(-120deg) translateY(-21.5vw) rotate(120deg);
}

.all-players>view>view:nth-child(3):nth-last-child(2) {
  transform: translate(-50%, -50%) rotate(-210deg) translateY(-21.5vw) rotate(210deg);
}

.all-players>view>view:nth-child(4):nth-last-child(1) {
  transform: translate(-50%, -50%) rotate(-300deg) translateY(-21.5vw) rotate(300deg);
}

/* 6个头像 - 六边形排列 */
.all-players>view>view:nth-child(1):nth-last-child(6) {
  transform: translate(-50%, -50%) rotate(-30deg) translateY(-21vw) rotate(30deg);
}

.all-players>view>view:nth-child(2):nth-last-child(5) {
  transform: translate(-50%, -50%) rotate(-90deg) translateY(-21vw) rotate(90deg);
}

.all-players>view>view:nth-child(3):nth-last-child(4) {
  transform: translate(-50%, -50%) rotate(-150deg) translateY(-21vw) rotate(150deg);
}

.all-players>view>view:nth-child(4):nth-last-child(3) {
  transform: translate(-50%, -50%) rotate(-210deg) translateY(-21vw) rotate(210deg);
}

.all-players>view>view:nth-child(5):nth-last-child(2) {
  transform: translate(-50%, -50%) rotate(-270deg) translateY(-21vw) rotate(270deg);
}

.all-players>view>view:nth-child(6):nth-last-child(1) {
  transform: translate(-50%, -50%) rotate(-330deg) translateY(-21vw) rotate(330deg);
}

.all-players>view>view>text {
  position: absolute;
  background-color: #fed847;
  font-size: 8px;
  border-radius: 10px;
  padding: 1px 0px;
  bottom: -20%;
  left: calc(50% - 15px);
  width: 30px;
  text-align: center;
  color: #333;
}

.choose-side {
  display: flex;
}

.choose-side>view {
  width: 50%;
}

.choose-side>view:first-child>view {
  background: linear-gradient(270deg, #6a1212 0%, rgba(74, 0, 0, 0) 100%);
}

.choose-side>view:last-child>view {
  background: linear-gradient(270deg, rgba(13, 0, 74, 0) 0%, #172a86 100%);
}

.choose-side-left-item,
.choose-side-right-item {
  display: flex;
  align-items: center;
  color: #fff;
  border-radius: 12px;
  padding: 10px;
  align-items: center;
  margin: 10px 5px;
  position: relative;
}

.choose-side-left-item {
  justify-content: flex-end;
}

.choose-side-left-item>text,
.choose-side-right-item>text,
.team-player-name {
  margin: 10px;
  max-width: 100px;
  font-size: 14px;
}

.team-player-name .member-nickname__text,
.team-player-name .member-nickname__shine {
  font-size: 14px;
}

.choose-side-left-item>button:first-child,
.choose-side-right-item>button:last-child {
  position: absolute;
  top: 0;
}

.choose-side-left-item>button:first-child>image,
.choose-side-right-item>button:last-child>image {
  width: 28px;
}

.choose-side-left-item>button:first-child {
  left: 0;
}

.choose-side-right-item>button:last-child {
  right: 0;
}

.choose-side-left-item>button:last-child,
.choose-side-right-item>button:first-child {
  background-color: #fff;
  border-radius: 50%;
  width: 38px;
  height: 38px;
  display: flex;
  justify-content: center;
  align-items: center;
  margin-bottom: 14rpx;
}

.choose-side-left-item>button:last-child>image,
.choose-side-right-item>button:first-child>image {
  width: 18px;
}

.team-player-avatar {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.team-player-avatar>text {
  font-size: 16rpx;
  border-radius: 20rpx;
  line-height: 26rpx;
  padding: 0 10rpx;
  margin-top: -16rpx;
  position: relative;
  background-color: #2c261fb3;
  border: 1rpx solid #a3793f66;
  color: #fed847;
}

.guide-tips__target {
  font-weight: 400;
  font-size: 26rpx;
  color: rgba(255, 217, 71, 0.8);
}

.guide-tips__warn {
  font-weight: 400;
  font-size: 22rpx;
  color: rgba(255, 255, 255, 0.8);
  margin-top: 6rpx;
}

.guide-tips {
  display: flex;
  flex-direction: column;
  padding-left: 20rpx;
}
</style>
