import {
  asyncDelay,
  asyncPlayDragonBoneAnimation,
  asyncTweenTo,
  onHomeworkFinish,
  RandomInt,
} from "../script/util";
import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";
import { NetworkHelper } from "../script/NetworkHelper";
import { GameServer } from "../script/Server";

const { ccclass, property } = cc._decorator;

@ccclass
export default class SceneComponent extends MyCocosSceneComponent {
  @property(cc.Prefab)
  loadingLayerPrefab = null;

  addPreloadImage() {
    // TODO 根据自己的配置预加载图片资源
    // this._imageResList.push({ url: this.data.pic_url });
  }

  addPreloadAudio() {
    // TODO 根据自己的配置预加载音频资源
    this._audioResList.push({ url: this.data.gameStartAudio });
    this._audioResList.push({ url: this.data.gameLoadingAudio });
    this._audioResList.push({ url: this.data.waitingWheel });
    this._audioResList.push({ url: this.data.waitingPiece });
    this._audioResList.push({ url: this.data.waitingTurn });
  }

  addPreloadAnima() { }

  onLoadEnd() {
    // TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考

    this.log("onLoadEnd");
    this.initData();
    this.initView();
    this.initListener();
  }

  _status = {
    Red: 0,
    Blue: 0,
    letter: "",
    current: "Blue",
  };
  playerId;
  isRoomOwner;
  server: GameServer;
  networkHelper: NetworkHelper;
  async initData() {
    this.networkHelper = new NetworkHelper();
    this.initNetworkListener();
    do {
      this.playerId = await this.networkHelper.init("op_16_2", 2);
      if (this.playerId === null) {
        console.log("onDestroy");
        this.networkHelper.onDestroy();
      }
      console.log("this.playerId = " + this.playerId);
    } while (this.playerId === null);

    const room = this.networkHelper.room;
    if (this.playerId == room.roomInfo.owner) {
      console.log("房主");
      this.isRoomOwner = true;
      this.server = new GameServer(2, this.networkHelper);
      this.server.jumpList = this.getJumpList();
      await this.networkHelper.startFrameSync();
      this.server.addPlayer({
        uuid: this.playerId,
        isAI: false,
      });
      this.server.startMatch();
    }
  }

  initView() {
    this.initBg();
    this.initLoadingLayer();
    this.initPiece();
  }

  getJumpList() {
    const jumpList = [];
    cc.find('Canvas/bg/chessBoard/boardItems').children.forEach(node => {
      const itemData = node.getComponent('ItemData');
      if (itemData.jump) {
        const from = itemData.idx;
        const to = itemData.jump;
        jumpList.push({ from, to });
      }
    });
    return jumpList;
  }

  initBg() {
    const canvas = cc.find("Canvas");
    const bgImg = cc.find("Canvas/bgImg");
    bgImg.scale = Math.max(
      canvas.width / bgImg.width,
      canvas.height / bgImg.height
    );

    const bg = cc.find("Canvas/bg");
    bg.scale = Math.min(canvas.width / bg.width, canvas.height / bg.height);

    const chessBoardBg = cc.find("Canvas/bg/chessBoard/bg");

    const offsetX =
      (chessBoardBg.width * chessBoardBg.scaleX) / 2 +
      (canvas.width - chessBoardBg.width * chessBoardBg.scaleX) / 4;
    const lifeblue = cc.find("Canvas/bg/Lifeblue");
    lifeblue.x = -offsetX;
    const lifered = cc.find("Canvas/bg/Lifered");
    lifered.x = offsetX;
  }

  loadingLayer;
  initLoadingLayer() {
    const loadingLayerBase = cc.find("Canvas/bg/loadingLayerBase");

    const loadingLayerNode = cc.instantiate(this.loadingLayerPrefab);
    loadingLayerBase.addChild(loadingLayerNode);

    this.loadingLayer = loadingLayerNode.getComponent("LoadingLayer");
    this.loadingLayer.setMaxPlayerNumber(2);
    this.loadingLayer.onLoadFinished(() => {
      this.playAudioByUrl(this.data.gameStartAudio);
    });

    this.playAudioByUrl(this.data.gameLoadingAudio);
  }

  blinkTheDice() {
    const dice = cc.find("Canvas/bg/chessBoard/diceBg/hatBlink");
    cc.tween(dice)
      .set({ opacity: 0 })
      .to(0.2, { opacity: 255 })
      .to(0.2, { opacity: 0 })
      .union()
      .repeatForever()
      .start();

    cc.find("Canvas/bg/chessBoard/diceBg").children.forEach((node) => {
      cc.tween(node)
        .set({ scale: 1 })
        .to(0.2, { scale: 1.1 })
        .to(0.2, { scale: 1.0 })
        .union()
        .repeatForever()
        .start();
    });

    const dice2 = cc.find("Canvas/bg/chessBoard/diceBg/dice");
    dice2["canClick"] = true;
  }

  stopBlinkTheDice() {
    const dice = cc.find("Canvas/bg/chessBoard/diceBg/hatBlink");
    dice.stopAllActions();
    cc.find("Canvas/bg/chessBoard/diceBg").children.forEach((node) => {
      node.stopAllActions();
      node.scale = 1;
      node.opacity = 255;
    });
    const dice2 = cc.find("Canvas/bg/chessBoard/diceBg/dice");
    dice2["canClick"] = false;
  }

  greyDice() {
    cc.find("Canvas/bg/chessBoard/diceBg").children.forEach((node) => {
      node.color = cc.color(150, 150, 150);
    });
  }

  stopGreyDice() {
    cc.find("Canvas/bg/chessBoard/diceBg").children.forEach((node) => {
      node.color = cc.color(255, 255, 255);
    });
  }

  initPiece() {
    const offsetX = { Red: -45, Blue: 45 };
    const offsetY = { Red: -90, Blue: -90 };
    const board = cc.find("Canvas/bg/chessBoard/boardItems");

    const pieceNodeRed = cc.find(`Canvas/bg/chessBoard/pieceRed`);
    const startIdxRed = this._status["Red"];
    const boardNodeRed = board.children[startIdxRed];
    pieceNodeRed.x = boardNodeRed.x + offsetX.Red;
    pieceNodeRed.y = boardNodeRed.y + offsetY.Red;

    const pieceNodeBlue = cc.find(`Canvas/bg/chessBoard/pieceBlue`);
    const startIdxBlue = this._status["Blue"];
    const boardNodeBlue = board.children[startIdxBlue];
    pieceNodeBlue.x = boardNodeBlue.x + offsetX.Blue;
    pieceNodeBlue.y = boardNodeBlue.y + offsetY.Blue;
  }

  initListener() {
    const btn = cc.find("Canvas/bg/New Button");
    btn.on("click", async () => {
      const idx = RandomInt(6);
      await this.rollTheDice(idx);
      this._status.letter = ["G", "H", "I", "J", "K", "L"][idx];
    });

    const dice = cc.find("Canvas/bg/chessBoard/diceBg/dice");
    dice.on("click", () => {
      if (this._status.letter != "") {
        return;
      }
      if (!dice["canClick"]) {
        return;
      }
      const playerMe = this.allPlayerList.find(
        (player) => player.uuid == this.playerId
      );

      if (this._status.current == playerMe.color) {
        this.networkHelper.sendFrame({
          type: "roll",
          uuid: playerMe.uuid,
        });
      }
    });

    const pieceBlue = cc.find("Canvas/bg/chessBoard/pieceBlue");
    this.addPieceTouchEventListener(pieceBlue, "Blue");

    const pieceRed = cc.find("Canvas/bg/chessBoard/pieceRed");
    this.addPieceTouchEventListener(pieceRed, "Red");

    const coolCat = cc.find("Canvas/bg/tree/catBase/cat");
    const catBtn = cc.find("Canvas/bg/tree/catBase/catBtn");
    catBtn.on("click", async () => {
      asyncPlayDragonBoneAnimation(coolCat, "begin");
      const playerMe = this.allPlayerList.find(
        (player) => player.uuid == this.playerId
      );
      if (playerMe.color == this._status.current) {
        if (this._status.letter == "") {
          await this.playAudioByUrl(this.data.waitingWheel);
        } else {
          await this.playAudioByUrl(this.data.waitingPiece);
        }
      } else {
        await this.playAudioByUrl(this.data.waitingTurn);
      }
      asyncPlayDragonBoneAnimation(coolCat, "normal");
    });
  }

  addPieceTouchEventListener(node: cc.Node, color) {
    node.on(cc.Node.EventType.TOUCH_START, (event: cc.Event.EventTouch) => {
      const playerMe = this.allPlayerList.find(
        (player) => player.uuid == this.playerId
      );
      if (playerMe.color != this._status.current) {
        this.blinkPiece(node);
        return;
      }
      if (this._status.current != color) {
        this.blinkPiece(node);
        return;
      }
      if (this._status.letter == "") {
        this.blinkPiece(node);
        return;
      }
      if (node["cantMove"]) {
        this.blinkPiece(node);
        return;
      }
      this.stopRollPiece(node);
      node["touchStartPos"] = {
        nodeX: node.x,
        nodeY: node.y,
        touchX: event.getLocation().x,
        touchY: event.getLocation().y,
      };
      node.zIndex = 1;
      this.showStars(node);
    });
    node.on(cc.Node.EventType.TOUCH_MOVE, (event: cc.Event.EventTouch) => {
      const playerMe = this.allPlayerList.find(
        (player) => player.uuid == this.playerId
      );
      if (playerMe.color != this._status.current) {
        return;
      }
      if (this._status.current != color) {
        return;
      }
      if (this._status.letter == "") {
        return;
      }
      if (node["cantMove"]) {
        return;
      }
      const pos = event.getLocation();
      const touchStartPos = node["touchStartPos"];
      const worldNodePos = node.parent.convertToWorldSpaceAR(
        cc.v2(touchStartPos.nodeX, touchStartPos.nodeY)
      );
      const nodePos = node.parent.convertToNodeSpaceAR(
        cc.v2(
          worldNodePos.x + pos.x - touchStartPos.touchX,
          worldNodePos.y + pos.y - touchStartPos.touchY
        )
      );
      node.setPosition(nodePos);
    });
    node.on(cc.Node.EventType.TOUCH_END, async (event: cc.Event.EventTouch) => {
      const playerMe = this.allPlayerList.find(
        (player) => player.uuid == this.playerId
      );
      if (playerMe.color != this._status.current) {
        return;
      }
      if (this._status.current != color) {
        return;
      }
      if (this._status.letter == "") {
        return;
      }
      if (node["cantMove"]) {
        return;
      }
      node["cantMove"] = true;
      if (this.checkNodeInRightBlock(node, color)) {
        const idx = this.getNextRightIdx();
        const playerMe = this.allPlayerList.find(
          (player) => player.uuid == this.playerId
        );
        this.networkHelper.sendFrame({
          type: "right",
          idx: idx,
          uuid: playerMe.uuid,
          color: playerMe.color,
        });
      } else {
        const playerMe = this.allPlayerList.find(
          (player) => player.uuid == this.playerId
        );
        this.networkHelper.sendFrame({
          type: "wrong",
          uuid: playerMe.uuid,
          color: playerMe.color,
        });
      }
    });
  }

  blinkPiece(node) {
    if (node['rightTween']) {
      return;
    }
    node.stopAllActions();
    cc.tween(node)
      .set({ scale: 1 })
      .to(0.05, { scale: 1.05 })
      .to(0.05, { scale: 1 })
      .start();
  }

  rollPiece(node: cc.Node) {
    node.stopAllActions();
    cc.tween(node)
      .set({ scale: 1, angle: 0 })
      .to(0.1, { angle: -10 })
      .to(0.2, { angle: 10 })
      .to(0.1, { angle: 0 })
      .delay(1)
      .union()
      .repeatForever()
      .start();

    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    board.children.forEach((child: cc.Node, idx, list) => {
      cc.tween(child)
        .set({ scale: 1.34 })
        .delay(idx * 0.1)
        .to(0.1, { scale: 1.5 })
        .to(0.1, { scale: 1.34 })
        .delay(list.length * 0.2 - idx * 0.2)
        .start();
    });
  }
  stopRollPiece(node) {
    node.scale = 1;
    node.angle = 0;
    node.stopAllActions();
  }
  rollPieceOnce(node: cc.Node) {
    node.stopAllActions();
    cc.tween(node)
      .set({ scale: 1, angle: 0 })
      .to(0.1, { angle: -10 })
      .to(0.2, { angle: 10 })
      .to(0.1, { angle: 0 })
      .start();
  }

  getRightBlock() {
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const startIdx = this._status[this._status.current];
    console.log("startIdx = " + JSON.stringify(startIdx));
    for (let i = startIdx + 1; i < board.children.length; i++) {
      const targetNode = board.children[i];
      const itemData = targetNode.getComponent("ItemData");

      if (itemData.letter.toLowerCase() == this._status.letter.toLowerCase()) {
        return targetNode;
        // if(itemData.jump!=""){
        //   const jtNode=board.children[parseInt(itemData.jump)];
        //   return jtNode;
        // }
        // else{
        //   return targetNode;          
        // }  
      }
    }
    return null;
  }

  jumpBlock(idx) {
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const targetNode = board.children[idx];
    return targetNode;
  }

  getNextRightIdx() {
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const startIdx = this._status[this._status.current];
    for (let i = startIdx + 1; i < board.children.length; i++) {
      const targetNode = board.children[i];
      const itemData = targetNode.getComponent("ItemData");
      if (itemData.letter.toLowerCase() == this._status.letter.toLowerCase()) {
        return i;
      }
    }
    return -1;
  }

  checkNodeInRightBlock(node, color) {
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const startIdx = this._status[color];

    for (let i = startIdx + 1; i < board.children.length; i++) {
      const targetNode = board.children[i];
      const itemData = targetNode.getComponent("ItemData");

      if (itemData.letter.toLowerCase() == this._status.letter.toLowerCase()) {
        if (targetNode.getBoundingBox().intersects(node.getBoundingBox())) {
          return true;
        }
        return false;
      }
    }
    return false;
  }

  showStars(node) {
    cc.tween(node)
      .delay(0.07)
      .call(() => {
        const light = cc.instantiate(cc.find("nodes/light"));
        light.parent = node.parent;
        cc.tween(light)
          .set({
            x: node.x + RandomInt(200) - 100,
            y: node.y + 50,
            scale: 0,
          })
          .by(
            1,
            {
              y: 200 + RandomInt(200) - 100,
              scale: 0.7 + 0.3 * Math.random(),
            },
            { easing: "cubicOut" }
          )
          .removeSelf()
          .start();
      })
      .union()
      .repeatForever()
      .start();
  }

  async pieceFindRightBlock(rightBlock, idx) {
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const color = this._status.current;
    const piece = cc.find(`Canvas/bg/chessBoard/piece${color}`);
    const prograssbar = cc.find(
      `Canvas/bg/Life${color.toLowerCase()}/life_${color.toLowerCase()}/mask/prograssbar`
    );
    const mask = cc.find(
      `Canvas/bg/Life${color.toLowerCase()}/life_${color.toLowerCase()}/mask`
    );
    let targetHeight =
      (idx / (board.children.length - 2)) * prograssbar.height;

    console.log(idx + "_进度条高：" + targetHeight);
    const offsetX = { Red: -45, Blue: 45 };
    const offsetY = { Red: -90, Blue: -90 };

    this._status[color] = idx;
    await this.playLocalAudio("正确");

    piece.zIndex = 1;
    this.showStars(piece);

    piece['rightTween'] = true;
    await asyncTweenTo(piece, 1, {
      x: rightBlock.x + offsetX[color],
      y: rightBlock.y + offsetY[color],
    });
    piece['rightTween'] = false;

    for (let i = 0; i < 20; i++) {
      const star = cc.instantiate(cc.find("nodes/star"));
      star.parent = piece.parent;
      cc.tween(star)
        .set({
          x: piece.x,
          y: piece.y + 50,
          scale: 0,
        })
        .to(
          0.5,
          {
            x: piece.x + RandomInt(400) - 200,
            y: piece.y + 50 + RandomInt(400) - 200,
            scale: 0.3 + 0.2 * Math.random(),
            angle: RandomInt(720),
          },
          { easing: "cubicOut" }
        )
        .removeSelf()
        .start();
    }

    piece.stopAllActions();
    await this.playLocalAudio("落子");
    piece.zIndex = 0;

    const effectNode = cc.find(`Canvas/bg/Life${color.toLowerCase()}/effect`);
    effectNode.active = true;
    asyncTweenTo(mask, 1, { height: targetHeight }, { easing: "cubicInOut" });
    this.playLocalAudio("进度条升高");
    await asyncPlayDragonBoneAnimation(effectNode, "normal", 1);
    effectNode.active = false;
  }

  updateStatus(status = null) {
    if (status) {
      console.log(status);
      this._status = JSON.parse(JSON.stringify(status));
    } else {
      console.log("喵喵喵");
    }
    const playerMe = this.allPlayerList.find(
      (player) => player.uuid == this.playerId
    );
    if (playerMe.color == this._status.current) {
      this.stopGreyDice();
      if (this._status.letter == "") {
        this.showYourTurn();
        this.blinkTheDice();
      } else {
        this.stopBlinkTheDice();

        this.rollPiece(this.getCurrentPiece());
      }
    } else {
      this.greyDice();
    }

    const blueFrame = cc.find("Canvas/bg/Lifeblue/faceFrame");
    const redFrame = cc.find("Canvas/bg/Lifered/faceFrame");
    let blinkFrame: cc.Node, stopBlinkFrame: cc.Node;
    if (this._status.current == "Red") {
      blinkFrame = redFrame;
      stopBlinkFrame = blueFrame;
    } else {
      blinkFrame = blueFrame;
      stopBlinkFrame = redFrame;
    }
    blinkFrame.stopAllActions();
    cc.tween(blinkFrame)
      .set({ opacity: 100 })
      .to(1.5, { opacity: 255 }, { easing: "cubicOut" })
      .to(1.5, { opacity: 100 }, { easing: "cubicIn" })
      .union()
      .repeatForever()
      .start();
    stopBlinkFrame.stopAllActions();
    stopBlinkFrame.opacity = 0;
  }

  getCurrentPiece() {
    if (this._status.current == "Red") {
      return cc.find("Canvas/bg/chessBoard/pieceRed");
    } else {
      return cc.find("Canvas/bg/chessBoard/pieceBlue");
    }
  }

  changeSide() {
    if (this._status.current == "Red") {
      this._status.current = "Blue";
      console.log("changeSide Blue");
    } else {
      this._status.current = "Red";
      console.log("changeSide Red");
    }
  }

  showYourTurn() {
    return new Promise((resolve, reject) => {
      const yourTurn = cc.find("Canvas/bg/yourturn");
      yourTurn.active = true;
      cc.tween(yourTurn)
        .set({ opacity: 0, scale: 5 })
        .to(1, { opacity: 255, scale: 2 })
        .delay(0.5)
        .to(0.5, { opacity: 0 })
        .call(() => {
          resolve(null);
        })
        .start();
    });
  }

  async pieceGoBack(node) {
    const touchStartPos = node["touchStartPos"];
    if (!touchStartPos) {
      return;
    }

    this.playLocalAudio("错误弹回");
    await asyncTweenTo(
      node,
      0.7,
      { x: touchStartPos.nodeX, y: touchStartPos.nodeY },
      { easing: "cubicOut" }
    );
    node.stopAllActions();
  }

  allPlayerList;
  initNetworkListener() {
    this.networkHelper.on("playerJoin", (event) => {
      if (this.server) {
        this.server.onPlayerJoin(event);
      }
      cc.log("playerJoin" + JSON.stringify(event));
    });
    this.networkHelper.on("playerLeave", (event) => {
      cc.log("playerLeave" + JSON.stringify(event));
      cc.find("Canvas/bg/PlayerOffLineLayer").active = true;
      this.networkHelper.leaveRoom();
    });
    this.networkHelper.on("playerOffLine", (event) => {
      cc.find("Canvas/bg/PlayerOffLineLayer").active = true;
      this.networkHelper.leaveRoom();
      this.log("playerOffLine" + JSON.stringify(event));
    });
    this.networkHelper.on("gameStart", (event) => { });
    this.networkHelper.on("frameEvent", (event) => {
      event.data.frame.items.forEach(async (item) => {
        if (this.server) {
          this.server.onFrameEvent(item.data);
        }

        if (item.data.type == "SERVER_allPlayerInfo") {
          console.log(
            "SERVER_allPlayerInfo: " + JSON.stringify(item.data.playerData)
          );
          item.data.playerData.forEach((player) => {
            if (!this.allPlayerList) {
              this.allPlayerList = [];
            }

            if (
              !this.allPlayerList.find(
                (listPlayer) => listPlayer.uuid == player.uuid
              )
            ) {
              this.allPlayerList.push({
                uuid: player.uuid,
                name: player.name,
                color: player.color,
                headUrl: player.headUrl,
              });
            }

            this.loadPlayerHeadImage();

            this.loadingLayer.addPlayer(
              player.name,
              player.uuid == this.playerId,
              player.headUrl,
              player.uuid
            );
          });
        } else if (item.data.type == "SERVER_updateStatus") {
          await asyncDelay(3);
          console.log(
            "SERVER_updateStatus: " + JSON.stringify(item.data.status)
          );
          this.updateStatus(item.data.status);
        } else if (item.data.type == "SERVER_playerRoll") {
          console.log("SERVER_playerRoll: " + JSON.stringify(item.data));
          const status = this._status;
          status.letter = item.data.letter;
          console.log("status.letter = " + status.letter);
          console.log("item.data.letter = " + item.data.letter);
          const idx = ["G", "H", "I", "J", "K", "L"].findIndex(
            (letter) => letter == status.letter
          );
          const pieceRed = cc.find("Canvas/bg/chessBoard/pieceRed");
          const pieceBlue = cc.find("Canvas/bg/chessBoard/pieceBlue");
          pieceRed["cantMove"] = true;
          pieceBlue["cantMove"] = true;
          this.stopBlinkTheDice();
          console.log("status1 = " + JSON.stringify(status));
          await this.rollTheDice(idx);
          pieceRed["cantMove"] = false;
          pieceBlue["cantMove"] = false;
          console.log("status2 = " + JSON.stringify(status));
          console.log("this._status = " + JSON.stringify(this._status));
          this.updateStatus(status);
          console.log("status = " + JSON.stringify(status));
          console.log("this._status = " + JSON.stringify(this._status));
        } else if (item.data.type == "SERVER_playerRight") {
          console.log("SERVER_playerRight: " + JSON.stringify(item.data));
          console.log("this._status = " + JSON.stringify(this._status));
          let rightBlock = this.getRightBlock();
          console.log(rightBlock);
          let idx = this.getNextRightIdx();
          console.log(idx);
          const pieceRed = cc.find("Canvas/bg/chessBoard/pieceRed");
          const pieceBlue = cc.find("Canvas/bg/chessBoard/pieceBlue");
          pieceRed["cantMove"] = false;
          pieceBlue["cantMove"] = false;
          await this.pieceFindRightBlock(rightBlock, idx);

          const riData = rightBlock.getComponent("ItemData");
          if (riData.jump != "") {
            rightBlock = this.jumpBlock(parseInt(riData.jump));
            idx = parseInt(riData.jump);//this.getNextRightIdx();
            await this.pieceFindRightBlock(rightBlock, idx);
          }

          pieceRed["cantMove"] = true;
          pieceBlue["cantMove"] = true;
          this._status.letter = "";
          this.changeSide();
          this.updateStatus();
        } else if (item.data.type == "SERVER_playerWrong") {
          console.log("SERVER_playerWrong: " + JSON.stringify(item.data));
          const node = cc.find(
            `Canvas/bg/chessBoard/piece${this._status.current}`
          );

          const playerMe = this.allPlayerList.find(
            (player) => player.uuid == this.playerId
          );
          if (playerMe.color == this._status.current) {
            await this.pieceGoBack(node);
          } else {
            this.rollPieceOnce(node);
          }

          node["cantMove"] = false;
          this._status.letter = "";
          this.changeSide();
          this.updateStatus();
        } else if (item.data.type == "SERVER_playerWin") {
          console.log("SERVER_playerWin: " + JSON.stringify(item.data));
          const node = cc.find(
            `Canvas/bg/chessBoard/piece${this._status.current}`
          );
          const playerMe = this.allPlayerList.find(
            (player) => player.uuid == this.playerId
          );

          const board = cc.find("Canvas/bg/chessBoard/boardItems");
          const idx = board.children.length;
          const rightBlock = board.children[idx - 1];

          await this.pieceFindRightBlock(rightBlock, idx);
          if (playerMe.color == this._status.current) {
            this.showWin();
          } else {
            this.showLoss();
          }
        }
      });
    });
  }

  showWin() {
    cc.find("Canvas/endBg").active = true;
    const bg = cc.find("Canvas/endBg/bg");
    cc.tween(bg).to(1, { opacity: 100 }).start();
    const loss = cc.find("Canvas/endBg/labelBg/labelLoss");
    loss.active = false;
    this.playLocalAudio("胜利");
  }
  showLoss() {
    cc.find("Canvas/endBg").active = true;
    const bg = cc.find("Canvas/endBg/bg");
    cc.tween(bg).to(1, { opacity: 100 }).start();
    const win = cc.find("Canvas/endBg/labelBg/labelWin");
    win.active = false;
    this.playLocalAudio("失败");
  }

  loadPlayerHeadImage() {
    const red = cc.find("Canvas/bg/Lifered/faceRed");
    const blue = cc.find("Canvas/bg/Lifeblue/faceBlue");
    this.allPlayerList.forEach((player) => {
      this.getSpriteFrimeByUrl(player.headUrl, (sf) => {
        if (player.color == "Red") {
          red.getComponent(cc.Sprite).spriteFrame = sf;
        } else {
          blue.getComponent(cc.Sprite).spriteFrame = sf;
        }
      });
    });
  }

  async movePiece(letter, color) {
    const offsetX = { Red: -45, Blue: 45 };
    const offsetY = { Red: -90, Blue: -90 };
    const pieceNode = cc.find(`Canvas/bg/chessBoard/piece${color}`);
    const board = cc.find("Canvas/bg/chessBoard/boardItems");
    const startIdx = this._status[color];

    for (let i = startIdx + 1; i < board.children.length; i++) {
      const targetNode = board.children[i];
      const itemData = targetNode.getComponent("ItemData");

      const prograssbar = cc.find(
        `Canvas/bg/Life${color.toLowerCase()}/life_${color.toLowerCase()}/mask/prograssbar`
      );
      const mask = cc.find(
        `Canvas/bg/Life${color.toLowerCase()}/life_${color.toLowerCase()}/mask`
      );
      const targetHeight = (i / board.children.length) * prograssbar.height;
      this.playLocalAudio("movePiece 进度条升高");
      cc.tween(mask)
        .to(1, { height: targetHeight }, { easing: "cubicInOut" })
        .start();

      await asyncTweenTo(
        pieceNode,
        1,
        {
          x: targetNode.x + offsetX[color],
          y: targetNode.y + offsetY[color],
        },
        { easing: "cubicInOut" }
      );

      if (itemData.letter.toLowerCase() == letter.toLowerCase()) {
        this._status[color] = i;

        return;
      }
    }
    this.finish();
  }

  finish() {
    onHomeworkFinish();
  }

  rollTheDice(num) {
    const dice = cc.find("Canvas/bg/chessBoard/diceBg/dice");
    if (dice["cantRoll"]) {
      return;
    }
    return new Promise((resolve, reject) => {
      const targetAngle = Math.ceil(dice.angle / 360 + 1) * 360;
      const time = (targetAngle - 360 - dice.angle) / 360;

      dice["cantRoll"] = true;

      cc.tween(dice)
        .by(3, { angle: 360 }, { easing: "cubicIn" })
        .to(time, { angle: targetAngle })
        .by(1, { angle: 360 })
        .by(1, { angle: 360 })
        .by(1, { angle: 360 })
        .by(1, { angle: 360 })
        .by((1 / 6) * num, { angle: 60 * num })
        .by(3, { angle: 360 }, { easing: "cubicOut" })
        .call(() => {
          dice["cantRoll"] = false;
          resolve(null);
        })
        .start();
    });
  }

  playLocalAudio(audioName) {
    const audio = cc
      .find(`audioClips/${audioName}`)
      .getComponent(cc.AudioSource);
    return new Promise((resolve, reject) => {
      const id = cc.audioEngine.playEffect(audio.clip, false);
      cc.audioEngine.setFinishCallback(id, () => {
        resolve(id);
      });
    });
  }

  // 生命周期
  onDestroy() {
    this.networkHelper.onDestroy();
  }
}
