<script setup>
import { ref, watch, onMounted, onUnmounted } from "vue";
import { onLoad, onShow, onHide } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import PlayerSeats from "@/components/PlayerSeats.vue";
import Guide from "@/components/Guide.vue";
import Timer from "@/components/Timer.vue";
import SButton from "@/components/SButton.vue";
import BowTarget from "@/components/BowTarget.vue";
import BattleHeader from "@/components/BattleHeader.vue";
import BattleFooter from "@/components/BattleFooter.vue";
import BowPower from "@/components/BowPower.vue";
import ShootProgress from "@/components/ShootProgress.vue";
import PlayersRow from "@/components/PlayersRow.vue";
import SModal from "@/components/SModal.vue";
import ScreenHint from "@/components/ScreenHint.vue";
import RoundEndTip from "@/components/RoundEndTip.vue";
import TestDistance from "@/components/TestDistance.vue";
import PlayerScore from "@/components/PlayerScore.vue";
import {
  getRoomAPI,
  destroyRoomAPI,
  exitRoomAPI,
  startRoomAPI,
  getCurrentGameAPI,
} from "@/apis";
import { isGameEnded } from "@/util";
import { MESSAGETYPES, roundsName, getMessageTypeName } from "@/constants";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
const step = ref(1);
const seq = ref(0);
const battleId = ref("");
const room = ref({});
const roomNumber = ref("");
const owner = ref({});
const opponent = ref({});
const redTeam = ref([]);
const blueTeam = ref([]);
const currentShooterId = ref(0);
const players = ref([]);
const playersSorted = ref([]);
const currentRound = ref(1);
const totalRounds = ref(0);
const start = ref(false);
const startCount = ref(true);
const power = ref(0);
const scores = ref([]);
const blueScores = ref([]);
const tips = ref("即将开始...");
const roundResults = ref([]);
const redPoints = ref(0);
const bluePoints = ref(0);
const currentRedPoint = ref(0);
const currentBluePoint = ref(0);
const showRoundTip = ref(false);
const playersScores = ref({});
const showModal = ref(false);
const halfTimeTip = ref(false);
const isFinalShoot = ref(false);
const total = ref(15);
const battleType = ref(0);
const isEnded = ref(false);

watch(
  () => [players.value, playersScores.value],
  ([n_players, n_scores]) => {
    if (n_players.length) {
      playersSorted.value = Object.keys(n_scores)
        .sort((a, b) => n_scores[b].length - n_scores[a].length)
        .map((pid) => n_players.find((p) => p.id == pid));
    }
  },
  {
    deep: true, // 添加深度监听
    immediate: true,
  }
);

function recoverData(battleInfo) {
  uni.removeStorageSync("last-awake-time");
  battleId.value = battleInfo.id;
  battleType.value = battleInfo.config.mode;
  step.value = 2;
  if (battleInfo.status === 0) {
    const readyRemain = Date.now() / 1000 - battleInfo.startTime;
    console.log(`当前局已进行${readyRemain}秒`);
    if (readyRemain > 0) {
      setTimeout(() => {
        uni.$emit("update-timer", 15 - readyRemain);
      }, 200);
    }
    return;
  } else {
    step.value = 3;
    start.value = true;
  }
  if (battleInfo.config.mode === 1) {
    redTeam.value = battleInfo.redTeam;
    blueTeam.value = battleInfo.blueTeam;
    if (battleInfo.status !== 0) {
      bluePoints.value = 0;
      redPoints.value = 0;
      currentRound.value = battleInfo.currentRound;
      totalRounds.value = battleInfo.maxRound;
      roundResults.value = battleInfo.roundResults;
      battleInfo.roundResults.forEach((round) => {
        const blueTotal = round.blueArrows.reduce(
          (last, next) => last + next.ring,
          0
        );
        const redTotal = round.redArrows.reduce(
          (last, next) => last + next.ring,
          0
        );
        if (blueTotal === redTotal) {
          bluePoints.value += 1;
          redPoints.value += 1;
        } else if (blueTotal > redTotal) {
          bluePoints.value += 2;
        } else {
          redPoints.value += 2;
        }
      });
      setTimeout(() => {
        if (battleInfo.roundResults[battleInfo.roundResults.length - 1]) {
          scores.value = battleInfo.roundResults[
            battleInfo.roundResults.length - 1
          ].redArrows.filter((item) => !!item.playerId);
          blueScores.value = battleInfo.roundResults[
            battleInfo.roundResults.length - 1
          ].blueArrows.filter((item) => !!item.playerId);
        }
      }, 300);
      if (
        battleInfo.redTeam[0].shotHistory[battleInfo.currentRound] ||
        battleInfo.blueTeam[0].shotHistory[battleInfo.currentRound]
      ) {
        roundResults.value.push({
          redArrows: battleInfo.redTeam[0].shotHistory[
            battleInfo.currentRound
          ].filter((item) => !!item.playerId),
          blueArrows: battleInfo.blueTeam[0].shotHistory[
            battleInfo.currentRound
          ].filter((item) => !!item.playerId),
        });
      } else if (battleInfo.currentRound < 5) {
        roundResults.value.push({
          redArrows: [],
          blueArrows: [],
        });
      }
    }
    // 这个状态不准
    // if (battleInfo.status !== 11) return;
    if (battleInfo.firePlayerIndex) {
      currentShooterId.value = battleInfo.firePlayerIndex;
      if (redTeam.value[0].id === currentShooterId.value) {
        tips.value = `请红队射箭-第${roundsName[currentRound.value]}轮`;
      } else {
        tips.value = `请蓝队射箭-第${roundsName[currentRound.value]}轮`;
      }
    }
    if (battleInfo.fireTime > 0) {
      const remain = Date.now() / 1000 - battleInfo.fireTime;
      console.log(`当前箭已过${remain}秒`);
      if (remain > 0 && remain < 15) {
        // 等渲染好再通知
        setTimeout(() => {
          uni.$emit("update-ramain", 15 - remain);
        }, 300);
      }
    }
  } else if (battleInfo.config.mode === 2) {
    total.value = 90;
    players.value = [...battleInfo.blueTeam, ...battleInfo.redTeam];
    players.value.forEach((p) => {
      playersScores.value[p.id] = [...p.arrows];
      if (p.id === user.value.id) scores.value = [...p.arrows];
    });
    if (battleInfo.status === 2) {
      startCount.value = true;
      const remain = Date.now() / 1000 - battleInfo.startTime;
      console.log(`当前局已进行${remain}秒`);
      tips.value = battleInfo.halfGame
        ? "下半场：请再射6箭"
        : "上半场：请先射6箭";
      setTimeout(() => {
        uni.$emit("update-ramain", 90 - remain);
      }, 300);
    } else if (battleInfo.status === 9) {
      startCount.value = false;
      tips.value = "准备下半场";
      setTimeout(() => {
        uni.$emit("update-ramain", 0);
      }, 300);
    }
  }
}

onLoad(async (options) => {
  if (options.battleId) {
    const battleInfo = uni.getStorageSync("current-battle");
    if (battleInfo) recoverData(battleInfo);
    setTimeout(getCurrentGameAPI, 2000);
  }
  if (options.roomNumber) {
    roomNumber.value = options.roomNumber;
    const result = await getRoomAPI(options.roomNumber);
    room.value = result;
    battleType.value = result.battleType;
    result.members.some((m) => {
      if (m.userInfo.id === result.creator) {
        owner.value = {
          id: m.userInfo.id,
          name: m.userInfo.name,
          avatar: m.userInfo.avatar,
        };
        return true;
      }
      return false;
    });
    if (result.battleType === 1) {
      if (user.value.id !== owner.value.id) {
        opponent.value = {
          id: user.value.id,
          name: user.value.nickName,
          avatar: user.value.avatar,
        };
      } else if (result.members.length > 1) {
        result.members.some((m) => {
          if (m.userInfo.id !== owner.value.id) {
            opponent.value = {
              id: m.userInfo.id,
              name: m.userInfo.name,
              avatar: m.userInfo.avatar,
            };
            return true;
          }
          return false;
        });
      }
    } else if (result.battleType === 2) {
      const ownerIndex = result.members.findIndex(
        (m) => m.userInfo.id === result.creator
      );
      if (ownerIndex !== -1) {
        players.value.push(result.members[ownerIndex].userInfo);
      } else {
        players.value.push({});
      }
      result.members.forEach((m, index) => {
        if (ownerIndex !== index) players.value.push(m.userInfo);
      });
    }
  }
});

const startGame = async () => {
  const result = await startRoomAPI(room.value.number);
  step.value = 2;
};

async function onReceiveMessage(messages = []) {
  messages.forEach((msg) => {
    if (
      msg.roomNumber === roomNumber.value ||
      (battleId.value && msg.id === battleId.value) ||
      msg.constructor === MESSAGETYPES.WaitForAllReady
    ) {
      console.log("收到消息：", getMessageTypeName(msg.constructor), msg);
    }
    if (msg.constructor === MESSAGETYPES.WaitForAllReady) {
      // 这里会掉多次;
      battleId.value = msg.id;
      step.value = 2;
      if (battleType.value === 1) {
        redTeam.value = msg.groupUserStatus.redTeam;
        blueTeam.value = msg.groupUserStatus.blueTeam;
      } else if (battleType.value === 2) {
        players.value = [
          ...msg.groupUserStatus.redTeam,
          ...msg.groupUserStatus.blueTeam,
        ];
        players.value.forEach((p) => {
          playersScores.value[p.id] = [];
        });
      }
    }
    if (msg.roomNumber === roomNumber.value) {
      if (msg.constructor === MESSAGETYPES.UserEnterRoom) {
        if (battleType.value === 1) {
          if (msg.userId === room.value.creator) {
            owner.value = {
              id: msg.userId,
              name: msg.name,
              avatar: msg.avatar,
            };
          } else {
            opponent.value = {
              id: msg.userId,
              name: msg.name,
              avatar: msg.avatar,
            };
          }
        }
        if (battleType.value === 2) {
          if (room.value.creator === msg.userId) {
            players.value[0] = {
              id: msg.userId,
              name: msg.name,
              avatar: msg.avatar,
            };
          } else {
            players.value.push({
              id: msg.userId,
              name: msg.name,
              avatar: msg.avatar,
            });
          }
        }
      }
      if (!start.value && msg.constructor === MESSAGETYPES.UserExitRoom) {
        if (battleType.value === 1) {
          if (msg.userId === room.value.creator) {
            owner.value = {
              id: "",
            };
          } else {
            opponent.value = {
              id: "",
            };
          }
        }
        if (battleType.value === 2) {
          players.value = players.value.filter((p) => p.id !== msg.userId);
        }
      }
      if (msg.constructor === MESSAGETYPES.RoomDestroy && !battleId.value) {
        uni.showToast({
          title: "房间已解散",
          icon: "none",
        });
        roomNumber.value = "";
        setTimeout(() => {
          uni.navigateBack();
        }, 1000);
      }
    }
    if (msg.id === battleId.value) {
      if (msg.constructor === MESSAGETYPES.AllReady) {
        start.value = true;
        totalRounds.value = msg.groupUserStatus.config.maxRounds;
        step.value = 3;
        roundResults.value.push({
          redArrows: [],
          blueArrows: [],
        });
        total.value = 15;
      }
      if (msg.constructor === MESSAGETYPES.MeleeAllReady) {
        start.value = true;
        startCount.value = true;
        step.value = 3;
        seq.value += 1;
        tips.value = scores.value.length
          ? "下半场：请再射6箭"
          : "上半场：请先射6箭";
        total.value = 90;
        halfTimeTip.value = false;
      }
      if (msg.constructor === MESSAGETYPES.ToSomeoneShoot) {
        if (battleType.value === 1) {
          if (currentShooterId.value !== msg.userId) {
            seq.value += 1;
            currentShooterId.value = msg.userId;
            if (redTeam.value[0].id === currentShooterId.value) {
              tips.value = "请红队射箭-";
            } else {
              tips.value = "请蓝队射箭-";
            }
            if (isFinalShoot.value) {
              tips.value += "决金箭";
            } else {
              tips.value += `第${roundsName[currentRound.value]}轮`;
            }
          }
        }
      }
      if (msg.constructor === MESSAGETYPES.ShootResult) {
        if (battleType.value === 1) {
          // 会有蓝队射箭时间，红队射箭也有结果返回的情况
          if (currentShooterId.value !== msg.userId) return;
          const isRed = redTeam.value.find((item) => item.id === msg.userId);
          if (isRed) scores.value.push(msg.target);
          else blueScores.value.push(msg.target);
          if (roundResults.value[currentRound.value - 1]) {
            if (isRed && roundResults.value[currentRound.value - 1].redArrows) {
              roundResults.value[currentRound.value - 1].redArrows.push(
                msg.target
              );
            }
            if (
              !isRed &&
              roundResults.value[currentRound.value - 1].blueArrows
            ) {
              roundResults.value[currentRound.value - 1].blueArrows.push(
                msg.target
              );
            }
          } else {
            roundResults.value.push({
              redArrows: [],
              blueArrows: [],
            });
          }
        }
        if (battleType.value === 2 && msg.userId === user.value.id) {
          scores.value.push({ ...msg.target });
          power.value = msg.target.battery;
        }
        if (playersScores.value[msg.userId])
          playersScores.value[msg.userId].push({ ...msg.target });
      }
      if (msg.constructor === MESSAGETYPES.CurrentRoundEnded) {
        if (battleType.value === 1) {
          const result = msg.preRoundResult;
          scores.value = [];
          blueScores.value = [];
          currentShooterId.value = 0;
          currentBluePoint.value = result.blueScore;
          currentRedPoint.value = result.redScore;
          bluePoints.value += result.blueScore;
          redPoints.value += result.redScore;
          currentRound.value = result.currentRound + 1;
          uni.$emit("update-ramain", 0);
          if (result.currentRound < 5) {
            roundResults.value.push({
              redArrows: [],
              blueArrows: [],
            });
            showRoundTip.value = true;
          }
        }
      }
      if (msg.constructor === MESSAGETYPES.FinalShoot) {
        if (!isFinalShoot.value) {
          isFinalShoot.value = true;
          showRoundTip.value = true;
          tips.value = "准备开始决金箭";
        }
      }
      if (msg.constructor === MESSAGETYPES.HalfTimeOver) {
        uni.$emit("update-ramain", 0);
        [
          ...msg.groupUserStatus.redTeam,
          ...msg.groupUserStatus.blueTeam,
        ].forEach((player) => {
          playersScores.value[player.id] = [...player.arrows];
          if (player.id === user.value.id) scores.value = [...player.arrows];
        });
        startCount.value = false;
        halfTimeTip.value = true;
        tips.value = "准备下半场";
      }
      if (msg.constructor === MESSAGETYPES.MatchOver) {
        uni.setStorageSync("last-battle", msg.endStatus);
        if (msg.endStatus.noSaved) {
          uni.showToast({
            title: "本场比赛无人射箭，已取消",
            icon: "none",
          });
          setTimeout(() => {
            uni.navigateBack();
          }, 1500);
        } else {
          isEnded.value = true;
          setTimeout(() => {
            uni.redirectTo({
              url: "/pages/battle-result",
            });
          }, 1500);
        }
      }
      if (msg.constructor === MESSAGETYPES.BackToGame) {
        uni.$emit("update-header-loading", false);
        if (msg.battleInfo) recoverData(msg.battleInfo);
      }
    }
  });
}

const destroyRoom = async () => {
  if (roomNumber.value) await destroyRoomAPI(roomNumber.value);
};

const exitRoom = async () => {
  uni.navigateBack();
};

const setClipboardData = () => {
  uni.setClipboardData({
    data: roomNumber.value,
    success() {
      uni.showToast({ title: "复制成功" });
    },
  });
};

const onBack = () => {
  if (battleId.value) {
    uni.$showHint(2);
  } else {
    showModal.value = true;
  }
};

onMounted(() => {
  uni.setKeepScreenOn({
    keepScreenOn: true,
  });
  uni.$on("socket-inbox", onReceiveMessage);
});

onUnmounted(() => {
  uni.setKeepScreenOn({
    keepScreenOn: false,
  });
  uni.$off("socket-inbox", onReceiveMessage);
  if (roomNumber.value && owner.value.id !== user.value.id && !battleId.value) {
    exitRoomAPI(roomNumber.value);
  }
});

const refreshTimer = ref(null);
onShow(async () => {
  if (battleId.value) {
    if (!isEnded.value && (await isGameEnded())) return;
    getCurrentGameAPI();
    const refreshData = () => {
      const lastAwakeTime = uni.getStorageSync("last-awake-time");
      if (lastAwakeTime) {
        getCurrentGameAPI();
      } else {
        clearInterval(refreshTimer.value);
      }
    };
    refreshTimer.value = setInterval(refreshData, 2000);
  }
});
onHide(() => {
  if (refreshTimer.value) clearInterval(refreshTimer.value);
  uni.setStorageSync("last-awake-time", Date.now());
});
</script>

<template>
  <Container title="对战" :onBack="onBack" :bgType="battleId ? 1 : 0">
    <view class="standby-phase" v-if="step === 1">
      <Guide>
        <view class="battle-guide">
          <view :style="{ display: 'flex', flexDirection: 'column' }">
            <text :style="{ color: '#fed847' }">弓箭手们，人都到齐了吗?</text>
            <text v-if="battleType === 1">1v1比赛即将开始! </text>
            <text v-if="battleType === 2">大乱斗即将开始! </text>
          </view>
          <view @click="setClipboardData">邀请好友</view>
        </view>
      </Guide>
      <view v-if="battleType === 1" class="team-mode">
        <image src="../static/1v1-bg.png" mode="widthFix" />
        <view>
          <view class="player" :style="{ transform: 'translateY(-60px)' }">
            <image
              :src="owner.avatar || '../static/user-icon.png'"
              mode="widthFix"
            />
            <text>{{ owner.name }}</text>
          </view>
          <image src="../static/versus.png" mode="widthFix" />
          <block v-if="opponent.id">
            <view class="player" :style="{ transform: 'translateY(60px)' }">
              <image
                :src="opponent.avatar || '../static/user-icon.png'"
                mode="widthFix"
              />
              <text v-if="opponent.name">{{ opponent.name }}</text>
            </view>
          </block>
          <block v-else>
            <view class="no-player">
              <image src="../static/question-mark.png" mode="widthFix" />
            </view>
          </block>
        </view>
      </view>
      <PlayerSeats
        v-if="battleType === 2"
        :total="room.count || 10"
        :players="players"
      />
      <view>
        <SButton
          v-if="user.id === owner.id && battleType === 1"
          :disabled="!opponent.id"
          :onClick="startGame"
          >进入对战</SButton
        >
        <SButton
          v-if="user.id === owner.id && battleType === 2"
          :disabled="players.length < 3"
          :onClick="startGame"
          >进入大乱斗</SButton
        >
        <SButton v-if="user.id !== owner.id" disabled>等待房主开启对战</SButton>
        <text class="tips">创建者点击下一步，所有人即可进入游戏。</text>
      </view>
    </view>
    <view v-if="step === 2" :style="{ width: '100%' }">
      <BattleHeader
        :blueTeam="blueTeam"
        :redTeam="redTeam"
        :players="players"
      />
      <TestDistance :guide="false" />
      <Timer />
    </view>
    <view v-if="step === 3" :style="{ width: '100%' }">
      <ShootProgress
        :tips="tips"
        :seq="seq"
        :start="players.length > 0 && start && startCount"
        :total="total"
        :currentRound="currentRound"
        :battleId="battleId"
        :melee="players.length > 0"
      />
      <PlayersRow
        v-if="blueTeam.length && redTeam.length"
        :blueTeam="blueTeam"
        :redTeam="redTeam"
        :currentShooterId="currentShooterId"
      />
      <BowTarget
        :mode="battleType === 1 ? 'team' : 'solo'"
        :power="start ? power : 0"
        :currentRound="scores.length"
        :totalRound="battleType === 1 ? 3 : totalRounds"
        :scores="scores"
        :blueScores="blueScores"
        :stop="!startCount"
      />
      <BattleFooter
        v-if="roundResults.length"
        :roundResults="roundResults"
        :redPoints="redPoints"
        :bluePoints="bluePoints"
      />
      <PlayerScore
        v-if="playersSorted.length"
        v-for="(player, index) in playersSorted"
        :key="index"
        :name="player.name"
        :avatar="player.avatar"
        :scores="playersScores[player.id] || []"
      />
    </view>
    <ScreenHint
      :show="showRoundTip"
      :onClose="() => (showRoundTip = false)"
      :mode="isFinalShoot ? 'tall' : 'normal'"
    >
      <RoundEndTip
        :isFinal="isFinalShoot"
        :round="currentRound - 1"
        :bluePoint="currentBluePoint"
        :redPoint="currentRedPoint"
        :roundData="
          roundResults[roundResults.length - 2]
            ? roundResults[roundResults.length - 2]
            : []
        "
        :onAutoClose="() => (showRoundTip = false)"
      />
    </ScreenHint>
    <ScreenHint
      :show="halfTimeTip"
      mode="small"
      :onClose="() => (halfTimeTip = false)"
    >
      <view class="half-time-tip">
        <text>上半场结束，休息一下吧:）</text>
        <text>20秒后开始下半场</text>
      </view>
    </ScreenHint>
    <SModal :show="showModal" :onClose="() => (showModal = false)">
      <view class="btns">
        <block v-if="!battleId">
          <SButton :onClick="exitRoom" width="200px" :rounded="20">
            暂时离开
          </SButton>
          <block v-if="owner.id === user.id">
            <view :style="{ height: '20px' }"></view>
            <SButton :onClick="destroyRoom" width="200px" :rounded="20">
              解散房间
            </SButton>
          </block>
        </block>
        <block v-else>
          <SButton :onClick="exitRoom" width="200px" :rounded="20">
            退出比赛
          </SButton>
        </block>
      </view>
    </SModal>
  </Container>
</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: 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: #fff9;
  font-size: 14px;
}
.player > image {
  width: 70px;
  height: 70px;
  border-radius: 50%;
  background-color: #ccc;
  margin-bottom: 5px;
}
.player > text {
  width: 100px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: center;
}
.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 > view:last-child {
  color: #fed847;
  border: 1px solid #fed847;
  margin-right: 10px;
  padding: 5px 12px;
  border-radius: 20px;
  position: relative;
}
</style>
