import { asyncDelay, RandomInt } from "../script/util";
import { AI } from "./AI";
import MsgData from "./msgDate";
import { MsgType, PlayerData, resultType } from "./msgType";
import { NetworkHelper } from "./NetworkHelper";

export class GameServer {
  playerList = [];
  playerMaxNumber = 0;
  networkHelper: NetworkHelper = null;
  nameList = [
    "Chris",
    "Benny",
    "Leslie",
    "Devin",
    "Sam",
    "Kerry",
    "Joey",
    "Hailey",
    "Fred",
    "Arrow",
    "Tony",
    "Michael",
  ];
  headUrls = [
    "http://staging-teach.cdn.ireadabc.com/0751c28419a0e8ffb1f0e84435b081ce.png",
    "http://staging-teach.cdn.ireadabc.com/f596e586a31ac2813b1702557941c022.png",
    "http://staging-teach.cdn.ireadabc.com/f0f396c52c42239913fd94523db979fa.png",
    "http://staging-teach.cdn.ireadabc.com/9f2d2ef622fa33d4e2abcbdc4b40ab6a.png",
    "http://staging-teach.cdn.ireadabc.com/f40ce4a8630039c4cf48a63fc1399c52.png",
  ];

  _checkList = [
    [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15],
    [0, 4, 8, 12], [1, 5, 9, 13], [2, 6, 10, 14], [3, 7, 11, 15],
    [0, 5, 10, 15], [3, 6, 9, 12]
  ]

  private _totalStep: any;
  randomList = [];
  wordList = [];
  _answerList = []
  private _useAI: boolean;
  private _timer: number;
  private _totalTime: number = 160;
  private _gameData: MsgData;
  private _userPrepareCount: number;
  private _lastTime: number;
  private _nowAnswerIndex: number;
  private _round_1_cardList: any[] = [];
  private _nowStepAnswerIndex: number;
  private _round2OutIndex;
  private _gameOver: boolean = false;

  constructor(playerMaxNumber, networkHelper) {
    this.playerMaxNumber = playerMaxNumber;
    this.networkHelper = networkHelper;

    this._timeoutIds = [];
    this._intervalIds = [];

    this.headUrls = this.headUrls.sort((a, b) => RandomInt(2) - 1);
    this.nameList = this.nameList.sort((a, b) => RandomInt(2) - 1);

    this._userPrepareCount = 0;
    this._gameData = new MsgData();
    this._gameData.Time = this._totalTime;
    this._gameData.Round = 1;
    this._gameOver = false;

    this.networkHelper.startFrameSync();
  }

  async addPlayer(player: PlayerData) {
    console.log("addPlayer");

    this._gameData.addPlayer({
      playerId: player.uuid,
      name: this.nameList.splice(0, 1)[0],
      uuid: player.uuid,
      side:
        player.uuid == this.networkHelper.room.roomInfo.owner ? "Red" : "Blue",
      isAI: player.isAI,
      headUrl: this.headUrls.splice(0, 1)[0],
    })

    this._senMsg({
      type: MsgType.USER_JOIN_EV,
      data: this._gameData.Msg
    });

    if (player.isAI) {
      this._useAI = true;
      await asyncDelay(1);
      if (this._gameData.PlayerList.length == this.playerMaxNumber) {
        this.networkHelper.closeRoom();
        await asyncDelay(0.5);
        this.startGame();
        this.startAI();
      }
    }
  }


  startGame() {


    let left = this.wordList.join(",").split(",");
    this._gameData.LeftList = left;
    console.log("========start game===========");
    this._senMsg({
      type: MsgType.ROOM_INIT_DONE,
      data: this._gameData.Msg
    });

    //this._senMsg({
    //   type: "SERVER_updateStatus",
    //   status: this.gameStatus,
    // });
  }

  onPlayerJoin(event) {
    // this.addPlayer({
    //   uuid: event.data.joinPlayerId,
    //   isAI: false,
    // });
  }

  _aiPlayerList = [];
  startMatch() {
    for (let i = 0; i < this.playerMaxNumber; i++) {
      this._timeoutIds.push(
        setTimeout(() => {
          let playerList = this._gameData.PlayerList;
          const count = this.playerMaxNumber - playerList.length;
          if (count > 0) {
            const playerInfo = {
              uuid: "ai_" + i,
              isAI: true,
            };
            this._aiPlayerList.push(new AI(this.networkHelper, playerInfo));
            this.addPlayer(playerInfo);
          }
        }, RandomInt(10000, 15000))
      );
    }
  }


  _senMsg(data: { type: MsgType, data: any }) {

    this.networkHelper.sendFrame({
      type: data.type,
      data: data.data
    });

    this._aiPlayerList.forEach((ai: AI) => {
      ai.onFrameEvent(data);
    });
  }

  _shecduleTimer() {

    let now = Date.now()
    this._gameData.Time -= (now - this._lastTime) / 1000;

    if (this._gameData.Time <= 0) {
      if (this._gameData.Round == 1) {
        let len = this._gameData.getAnswerList().length;
        for (let i = 0; i < 16 - len; ++i) {
          let index = Math.floor(Math.random() * (this.wordList.length * 0.99));
          let word = this.wordList[index];
          this.wordList.splice(index, 1);
          this._gameData.addAnswerList({ word: word, uuid: "none" })
        }

        clearInterval(this._timer)

        // this._senMsg({
        //   type: MsgType.ROOM_ST,
        //   data: this._gameData.Msg
        // });

        let answerList = this._gameData.getAnswerList();
        for (let i = 0; i < answerList.length; ++i) {
          this._round_1_cardList.push(answerList[i].word);
        }

        this._senMsg({
          type: MsgType.ROUND_END_EV,
          data: { round: this._gameData.Round, reason: 2, answerList: answerList }
        });
        this._initRound2();


      } else {


        this._senMsg({
          type: MsgType.USER_REQ_EV,
          data: { round: this._gameData.Round, uuid: "none", result: resultType.RIGHT, index: this._nowStepAnswerIndex, }
        })
        this._gameData.addAnswerList({ uuid: "none", index: this._nowStepAnswerIndex })

        this._initRound2Step();

      }


    } else {

      this._lastTime = now;
      this._senMsg({
        type: MsgType.ROOM_ST,
        data: this._gameData.Msg
      }

      );
    }
  }

  _initRound2() {
    this._gameData.Round = 2;
    this._round_1_cardList = [];
    let answerList = this._gameData.getAnswerList();
    for (let i = 0; i < answerList.length; ++i) {
      this._round_1_cardList.push(answerList[i].word);
    }
    this._gameData.clearAnswerList();
  }
  async _initRound2Step() {

    clearInterval(this._timer)

    let ary: Array<any> = this._checkRound2Over()
    if (ary.length > 0) {

      this._senMsg({
        type: MsgType.ROOM_ST,
        data: this._gameData.Msg
      })

      let realRedScore = (Math.floor(this._gameData.RedScore / 100) + this._gameData.RedScore % 100);
      let realBlueScore = (Math.floor(this._gameData.BuleSocre / 100) + this._gameData.BuleSocre % 100);

      let winSide = "Red"
      if (realBlueScore > realRedScore) {
        winSide = "Blue"
      } else if (realRedScore == realBlueScore) {
        let answerList = this._gameData.getAnswerList();
        for (let i = answerList.length - 1; i >= 0; ++i) {
          let answer = answerList[i];
          let uuid = answer.uuid;
          if (uuid == "none") continue;

          this._gameData.PlayerList.forEach((player) => {
            if (player.uuid == uuid) {
              winSide = player.side;
            }
          })

          break;

        }
      }

      let uuid = "";
      this._gameData.PlayerList.forEach((player) => {
        if (player.side == winSide) {
          uuid = player.uuid;
        }
      })

      this._gameOver = true;
      this._senMsg({
        type: MsgType.ROUND_END_EV,
        data: { round: this._gameData.Round, redScore: this._gameData.RedScore, blueScore: this._gameData.BuleSocre, uuid: uuid, ary: ary }
      })

      return;
    }


    this._nowStepAnswerIndex = this._getNewStepIndex();
    this._senMsg({
      type: MsgType.ROUND_START_EV,
      data: { round: this._gameData.Round, index: this._nowStepAnswerIndex }
    });

    await asyncDelay(1)

    if (this._gameOver) return;

    this._userPrepareCount = 0;
    this._lastTime = Date.now();
    this._gameData.Time = 10;
    this._shecduleTimer();
    this._timer = setInterval(this._shecduleTimer.bind(this), 1000);

  }
  _getNewStepIndex() {
    this._round2OutIndex = this._round2OutIndex || [];
    let index;
    do {
      index = Math.floor(Math.random() * this._round_1_cardList.length * 0.99);
    } while (this._round2OutIndex.indexOf(index) > -1)
    this._round2OutIndex.push(index)
    return index;
  }
  _checkRound2Over() {
    let gameAnswerList = this._gameData.getAnswerList();
    if (gameAnswerList.length < 4) return [];

    for (let i = 0; i < this._checkList.length; ++i) {
      let done = true;
      let ary = this._checkList[i];
      for (let k = 0; k < ary.length; ++k) {
        done = done && gameAnswerList.some((val) => {
          return val.index == ary[k]
        })
      }
      if (done) return ary;
    }
    return [];
  }
  async onFrameEvent(data) {
    // if (this.gameStatus['gameOver']) {
    //   return;
    // }
    let type: MsgType = data.type;
    let msgDate = data.data;

    if (type == MsgType.USER_JOIN_ERQ) {
      this.addPlayer(<PlayerData>msgDate)
    }
    else if (type == MsgType.USER_PREPARE_REQ) {

      if (this._gameData.Round == 1) {
        this._userPrepareCount++;
        if (this._userPrepareCount == this.playerMaxNumber - (this._useAI ? 1 : 0)) {
          this._senMsg({
            type: MsgType.ROUND_START_EV,
            data: { round: this._gameData.Round }
          });
          this._userPrepareCount = 0;
          this._lastTime = Date.now();
          this._shecduleTimer();
          this._timer = setInterval(this._shecduleTimer.bind(this), 1000)
        }
      } else {
        this._userPrepareCount++;
        if (this._userPrepareCount == this.playerMaxNumber - (this._useAI ? 1 : 0)) {
          this._initRound2Step();
        }

      }

    }
    else if (type == MsgType.USER_REQ_ERQ) {

      if (this._gameData.Round == 1) {

        let userId = msgDate.uuid;
        let word = msgDate.word;

        cc.log("uuid=" + userId + " input words =" + word);

        //todo 判断单词是否正确
        let index1 = this.wordList.indexOf(word);
        let index2 = this._answerList.indexOf(word);

        let result = resultType.WRONG;
        if (index1 > -1) {
          result = resultType.RIGHT;
          this._answerList.push(word);
          this.wordList.splice(index1, 1);

          let left = this.wordList.join(",").split(",");
          this._gameData.LeftList = left;
          this._gameData.addAnswerList({ word: word, uuid: userId });
          let side = "Red";
          this._gameData.PlayerList.forEach((player) => {
            if (player.uuid == userId) {
              side = player.side;
            }
          })
          this._gameData.RedScore += (side == "Red" ? 1 : 0);
          this._gameData.BuleSocre += (side == "Blue" ? 1 : 0);

        } else if (index2 > -1) {
          result = resultType.REPEAT;
        }
        this._senMsg({
          type: MsgType.USER_REQ_EV,
          data: { round: this._gameData.Round, uuid: userId, result: result }
        });

        if (this._gameData.getAnswerList().length == 16) {
          this._senMsg({
            type: MsgType.ROOM_ST,
            data: this._gameData.Msg
          });
          let answerList = this._gameData.getAnswerList();
          this._senMsg({
            type: MsgType.ROUND_END_EV,
            data: { round: this._gameData.Round, reason: 1, answerList: answerList }
          });
          clearInterval(this._timer)
          this._initRound2();

        } else {

          this._senMsg({
            type: MsgType.ROOM_ST,
            data: this._gameData.Msg
          });

        }

      } else {
        let userId = msgDate.uuid;
        let index = msgDate.index;

        if (index == this._nowStepAnswerIndex) {

          this._senMsg({
            type: MsgType.USER_REQ_EV,
            data: { round: this._gameData.Round, uuid: userId, result: resultType.RIGHT, index: index, }
          })

          let side = "";
          this._gameData.PlayerList.forEach((player) => {
            if (player.uuid == userId) {
              side = player.side;
            }
          })

          this._gameData.RedScore += (side == "Red" ? 100 : 0);
          this._gameData.BuleSocre += (side == "Blue" ? 100 : 0);

          this._gameData.addAnswerList({ uuid: userId, index: index })

          clearInterval(this._timer)

          await asyncDelay(1)
          this._initRound2Step();

        } else {

          this._senMsg({
            type: MsgType.USER_REQ_EV,
            data: { round: this._gameData.Round, uuid: userId, result: resultType.WRONG, index: index, }
          })
        }


      }



    }
    // else if (type == MsgType.USER_REQ_ERQ) {

    // }

    // let sender = this.playerList.find(p => p.uuid == data.uuid);
    // if (sender) {
    //   sender.name = data.playerName;
    //   sender.headUrl = data.playerHeadUrl;
    // }
    // if (data.type == "playerInfo") {

    //  this._senMsg({
    //     type: "SERVER_allPlayerInfo",
    //     playerData: this.playerList,
    //     status: this.gameStatus,
    //   });
    //   if (this.playerList.length == this.playerMaxNumber) {
    //     this.networkHelper.closeRoom();
    //     await asyncDelay(0.5);
    //     this.startGame();
    //     this.startAI();
    //   }
    // }
    // else if (data.type == "roll") {
    //   if (!data.uuid) {
    //     console.warn("data no uuid");
    //     return;
    //   }

    //   if (sender.color == this.gameStatus.current) {

    //     let i = Math.floor(Math.random() * this.randomList.length)
    //     let index = this.randomList[i];

    //     console.log("random index ===" + index);
    //     this.gameStatus.step = index;
    //     this.gameStatus.state = 1;


    //    this._senMsg({
    //       type: "SERVER_playerRoll",
    //       status: this.gameStatus,
    //     });


    //   } else {
    //     console.warn("data  uuid not match");
    //   }
    // }
    // else if (data.type == "right") {

    //   let posIndex = this.gameStatus.step
    //   this.gameStatus[this.gameStatus.current]++;
    //   let lastTime = +this.gameStatus.time;
    //   console.log("lasttime  = " + lastTime);
    //   let costTime = (Math.floor(Date.now() / 1000) - lastTime).toFixed(1)
    //   console.log("=right===cost time = " + costTime);
    //   if (this.gameStatus.current == "Red") {
    //     this.gameStatus.RedTime += +costTime
    //   } else {
    //     this.gameStatus.BlueTime += +costTime
    //   }

    //   let i = this.randomList.indexOf(posIndex);
    //   this.randomList[i] = this.randomList[this.randomList.length - 1];
    //   this.randomList.length--;

    //   if (this.gameStatus[this.gameStatus.current] < 10) {
    //     this.gameStatus.step = null;
    //     this.gameStatus.state = 2;
    //    this._senMsg({
    //       type: "SERVER_playerRight",
    //       status: this.gameStatus,
    //     });
    //     this.changeSide();
    //   } else {
    //     this.gameStatus.state = 2;
    //     this.gameStatus.step = null;
    //    this._senMsg({
    //       type: "SERVER_playerWin",
    //       status: this.gameStatus,
    //     });
    //     this.gameStatus['gameOver'] = true;
    //     clearTimeout(this._timer);
    //   }

    // } else if (data.type == "wrong") {

    //   let lastTime = +this.gameStatus.time;
    //   let costTime = (Math.floor(Date.now() / 1000) - lastTime).toFixed(1)
    //   console.log("=wrong and ===cost time = " + costTime);
    //   if (this.gameStatus.current == "Red") {
    //     this.gameStatus.RedTime += +costTime
    //   } else {
    //     this.gameStatus.BlueTime += +costTime
    //   }

    //   this.gameStatus.step = null;
    //   this.gameStatus.state = 2;

    //  this._senMsg({
    //     type: "SERVER_playerWrong",
    //     status: this.gameStatus,
    //   });
    //   this.changeSide();

    // } else if (data.type == "stateUpdate") {

    //   if (this._useAI || sender.color == this.gameStatus.current) {

    //     if (this.gameStatus.state == 2) {
    //       this.gameStatus.state = 0;
    //     }

    //     if (this.gameStatus.state == 0) {
    //       this.openTimerCounter();
    //     }

    //    this._senMsg({
    //       type: "SERVER_updateStatus",
    //       status: this.gameStatus,
    //     });

    //   }

    // }
    // else {
    //   this._aiPlayerList.forEach((ai: AI) => {
    //     ai.onFrameEvent(data);
    //   });
    // }
  }

  set TotalStep(step) {
    this._totalStep = step;
  }

  openTimerCounter() {

    let prepareTime = 4;
    // AI 无准备时间
    // if (this._useAI && this.gameStatus.current == "Blue") {
    //   prepareTime = 0
    // }
    // this.gameStatus.time = "" + (Math.floor(Date.now() / 1000) + prepareTime);
    // console.log(" openTimerCounter set time ------");
    // clearTimeout(this._timer)
    // let leftTime = this.gameStatus.BlueTime
    // if (this.gameStatus.current == "Red") {
    //   leftTime = this.gameStatus.RedTime;
    // }
    // leftTime = this._totalTime - leftTime + prepareTime;

    // console.log(`${this.gameStatus.current} left time  ${leftTime}, now time ${Date.now() / 1000}`)

    // this._timer = setTimeout(this.timeOver.bind(this), leftTime * 1000);
  }
  timeOver() {

    // let lastTime = +this.gameStatus.time;
    // let costTime = (Math.floor(Date.now() / 1000) - lastTime).toFixed(1)
    // console.log(`time over and time now ${Date.now() / 1000}`);
    // console.log("=wrong and ===cost time = " + costTime);
    // if (this.gameStatus.current == "Red") {
    //   this.gameStatus.RedTime += +costTime
    // } else {
    //   this.gameStatus.BlueTime += +costTime
    // }

    // if (this.gameStatus.current == "Red") {
    //   this.gameStatus.current = "Blue"
    // }
    // this.gameStatus.state = 2;
    // this.gameStatus.step = null;
    //this._senMsg({
    //   type: "SERVER_playerWin",
    //   status: this.gameStatus,
    // });
    // this.gameStatus['gameOver'] = true;

  }

  changeSide() {

    // console.log("=====changeSide=======");

    // console.log("=====old =======" + this.gameStatus.current);

    // if (this.gameStatus.current == "Red") {
    //   this.gameStatus.current = "Blue";
    // } else {
    //   this.gameStatus.current = "Red";
    // }

    // console.log("=====now =======" + this.gameStatus.current);
  }

  startAI() {
    this.playerList
      .filter((player) => player.isAI == true)
      .forEach((player) => { });
  }

  _timeoutIds = null;
  _intervalIds = null;
  // 生命周期
  onDestroy() {
    this._timeoutIds.forEach((id) => {
      clearTimeout(id);
    });
    this._intervalIds.forEach((id) => {
      clearInterval(id);
    });
  }
}
