<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import Matching from "@/components/Matching.vue";
import ModalDialog from "@/components/ModalDialog.vue";
import audioManager from "@/audioManager";
import { matchGameAPI, getBattleAPI } from "@/apis";
import { MESSAGETYPESV2 } from "@/constants";
import { isLimitError } from "@/util";
import { returnToBattle } from "@/utils/matchReturn";

const gameType = ref(0);
const teamSize = ref(0);
const onComplete = ref(null);
const showLimitModal = ref(false);
const navigationPending = ref(false);
let pageMounted = false;
let pageVisible = false;
let foregroundGeneration = 0;

/** 匹配超时计时器，用于检测 WS 消息丢失或真正超时 */
const matchTimeoutTimer = ref(null);

/** 匹配超时阈值（ms），后端设置 15s 匹配，前端预留 5s 冗余 */
const MATCH_TIMEOUT_MS = 20 * 1000;
const MATCH_INFO_RETRY_DELAY_MS = 500;

/** 清除超时计时器 */
const clearMatchTimeout = () => {
  if (matchTimeoutTimer.value) {
    clearTimeout(matchTimeoutTimer.value);
    matchTimeoutTimer.value = null;
  }
};

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;
    clearMatchTimeout();
    uni.redirectTo({
      url,
      success: resolve,
      fail: (error) => {
        navigationPending.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;
  return returnToBattle(battle, redirectOnce);
}

async function reconcileMatchingPage(generation) {
  clearMatchTimeout();

  let battle = null;
  try {
    battle = await queryCurrentBattle(generation);
  } catch (error) {
    if (!isCurrentForeground(generation)) return;
    console.log("resume 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 current match error", error);
      uni.showToast({
        title: "进入比赛失败，请重试",
        icon: "none",
      });
    }
    return;
  }

  if (!gameType.value || !teamSize.value) return;

  try {
    await matchGameAPI(true, gameType.value, teamSize.value);
    if (!isCurrentForeground(generation)) return;
    matchTimeoutTimer.value = setTimeout(handleMatchTimeout, MATCH_TIMEOUT_MS);
  } catch (error) {
    if (!isCurrentForeground(generation)) return;
    clearMatchTimeout();
    if (isLimitError(error)) {
      showLimitModal.value = true;
      return;
    }
    uni.navigateBack();
  }
}

/**
 * 超时处理：查询后端是否已分配对局
 * - 有对局 → WS 消息丢失场景，自动跳入
 * - 无对局 → 真正超时，提示用户并返回大厅
 */
const handleMatchTimeout = async () => {
  if (!pageVisible || navigationPending.value) return;
  try {
    const battle = await getBattleAPI();
    if (battle && battle.matchId) {
      uni.showToast({ title: "匹配成功，正在进入...", icon: "none" });
      await returnToCurrentBattle(battle);
    } else {
      uni.showToast({ title: "匹配超时，请重试", icon: "none" });
      try {
        if (gameType.value && teamSize.value) {
          await matchGameAPI(false, gameType.value, teamSize.value);
        }
      } catch (_) { /* 取消失败忽略 */ }
      uni.navigateBack();
    }
  } catch (e) {
    uni.showToast({ title: "匹配超时，请重试", icon: "none" });
    uni.navigateBack();
  }
};

async function stopMatch() {
  uni.$showHint(3);
}

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

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

/**
 * 取消匹配，带容错处理：
 * - 取消成功 → 返回大厅
 * - 取消失败（后端已分配对局但 WS 未到达）→ 查询并跳入当前对局
 */
async function cancelMatch() {
  if (navigationPending.value) return;
  foregroundGeneration += 1;
  clearMatchTimeout();
  try {
    if (gameType.value && teamSize.value) {
      await matchGameAPI(false, gameType.value, teamSize.value);
    }
    uni.navigateBack();
  } catch (e) {
    // 取消匹配接口失败，尝试查询是否已被分配对局
    try {
      const battle = await getBattleAPI();
      if (battle && battle.matchId) {
        await returnToCurrentBattle(battle);
      } else {
        uni.navigateBack();
      }
    } catch (_) {
      uni.navigateBack();
    }
  }
}

async function onReceiveMessage(msg) {
  if (msg.type === MESSAGETYPESV2.MatchSuccess) {
    onComplete.value = () => {}
  }
  if (msg.type === MESSAGETYPESV2.AboutToStart) {
    if (navigationPending.value) return;
    // 收到开始消息，清除超时计时器
    clearMatchTimeout();
    // 使用后端下发的 mode 字段判断跳转目标，与好友约战（battle-room.vue）保持一致
    // mode <= 3 为团队对抗，mode > 3 为大乱斗，覆盖全部 gameType（1~5），不再遗漏
    const matchId = msg.matchId || msg.id;
    if (!matchId) return;
    const url =
      msg.mode <= 3
        ? `/pages/team-battle/index?battleId=${matchId}`
        : `/pages/melee-battle?battleId=${matchId}`;
    try {
      await redirectOnce(url);
    } catch (error) {
      console.log("redirect to matched battle error", error);
    }
  }
}

onLoad(async (options) => {
  if (options.gameType && options.teamSize) {
    gameType.value = options.gameType;
    teamSize.value = options.teamSize;
  }
  if (pageMounted && pageVisible) {
    const generation = ++foregroundGeneration;
    void reconcileMatchingPage(generation);
  }
});

onMounted(() => {
  void audioManager.warmAll();
  uni.setKeepScreenOn({
    keepScreenOn: true,
  });
  uni.$on("socket-inbox", onReceiveMessage);
  uni.$on("cancelMatching", cancelMatch);
  pageMounted = true;
  if (pageVisible) void reconcileMatchingPage(foregroundGeneration);
});

onBeforeUnmount(() => {
  pageMounted = false;
  pageVisible = false;
  foregroundGeneration += 1;
  clearMatchTimeout();
  uni.setKeepScreenOn({
    keepScreenOn: false,
  });
  uni.$off("socket-inbox", onReceiveMessage);
  uni.$off("cancelMatching", cancelMatch);
});

onShow(() => {
  pageVisible = true;
  navigationPending.value = false;
  const generation = ++foregroundGeneration;
  clearMatchTimeout();
  if (pageMounted) void reconcileMatchingPage(generation);
});

onHide(() => {
  pageVisible = false;
  foregroundGeneration += 1;
  clearMatchTimeout();
});
</script>

<template>
  <Container title="搜索对手..." :bgType="1" :onBack="stopMatch">
    <view class="container">
      <Matching :stopMatch="stopMatch" :onComplete="onComplete" />
    </view>
  </Container>
  <ModalDialog
    :show="showLimitModal"
    :content="'今日排位赛次数已经用完\n开通会员可增加次数'"
    cancelText="知道了"
    confirmText="去开通"
    :onCancel="closeLimitModal"
    :onConfirm="goVipPage"
  />
</template>

<style scoped>
.container {
  width: 100%;
  height: 100%;
}
</style>
