import {
  onHomeworkFinish,
  randomSortByArr,
  playDragonBoneAnimation,
  asyncDelay,
  RandomInt,
} from "../script/util";
import { defaultData } from "../script/defaultData";
import { GameServer } from "./server";
import { NetworkHelper } from "./NetworkHelper";

cc.Class({
  extends: cc.Component,

  properties: {
    loadingLayerProfab: cc.Prefab,
  },

  // 生命周期 onLoad
  onLoad() {
    this._timeoutIds = [];
    this._intervalIds = [];
    this.initSceneData();
    this.initSize();
  },

  _imageResList: null,
  _audioResList: null,
  _animaResList: null,
  initSceneData() {
    this._imageResList = [];
    this._audioResList = [];
    this._animaResList = [];
  },

  _designSize: null, // 设计分辨率
  _frameSize: null, // 屏幕分辨率
  _mapScaleMin: null, // 场景中常用缩放（取大值）
  _mapScaleMax: null, // 场景中常用缩放（取小值）
  _cocosScale: null, // cocos 自缩放 （较少用到）
  initSize() {
    // 注意cc.winSize只有在适配后(修改fitHeight/fitWidth后)才能获取到正确的值,因此使用cc.getFrameSize()来获取初始的屏幕大小
    let screen_size =
      cc.view.getFrameSize().width / cc.view.getFrameSize().height;
    let design_size =
      cc.Canvas.instance.designResolution.width /
      cc.Canvas.instance.designResolution.height;
    let f = screen_size >= design_size;
    cc.Canvas.instance.fitHeight = f;
    cc.Canvas.instance.fitWidth = !f;

    const frameSize = cc.view.getFrameSize();
    this._frameSize = frameSize;

    this._designSize = cc.view.getDesignResolutionSize();

    let sx = cc.winSize.width / frameSize.width;
    let sy = cc.winSize.height / frameSize.height;
    this._cocosScale = Math.min(sx, sy);

    sx = frameSize.width / this._designSize.width;
    sy = frameSize.height / this._designSize.height;
    this._mapScaleMin = Math.min(sx, sy) * this._cocosScale;
    this._mapScaleMax = Math.max(sx, sy) * this._cocosScale;

    cc.director._scene.width = frameSize.width;
    cc.director._scene.height = frameSize.height;
  },

  // 生命周期 start
  start() {
    let getData = this.getData.bind(this);
    if (window && window.courseware) {
      getData = window.courseware.getData;
    }

    getData((data, aspect) => {
      this.log("data:" + JSON.stringify(data));
      this.log("aspect:" + JSON.stringify(aspect));
      this.aspect = aspect;
      this.data = data || this.getDefaultData();
      this.data = JSON.parse(JSON.stringify(this.data));
      this.preloadItem();
    });
  },

  getData(func) {
    if (window && window.courseware) {
      window.courseware.getData(func, "scene");
      return;
    }

    const middleLayer = cc.find("middleLayer");
    if (middleLayer) {
      const middleLayerComponent = middleLayer.getComponent("middleLayer");
      middleLayerComponent.getData(func);
      return;
    }

    func(this.getDefaultData());
  },

  getDefaultData() {
    return defaultData;
  },

  preloadItem() {
    this.addPreloadImage();
    this.addPreloadAudio();
    this.addPreloadAnima();
    this.preload();
  },

  addPreloadImage() {
    this._imageResList.push(
      ...this.data.question_arr
        .map((question) => {
          return question.option_arr.map((option) => {
            return option.pic_url;
          });
        })
        .flat()
    );
  },

  addPreloadAudio() {
    this._audioResList.push(this.data.startLoadingAudio);
    this._audioResList.push(this.data.startAudio);
    this._audioResList.push(this.data.endAudio);
    this._audioResList.push(...this.data.finishAudioList);
    this._audioResList.push(
      ...this.data.question_arr
        .map((question) => {
          return question.option_arr.map((option) => {
            return option.audio_url;
          });
        })
        .flat()
    );
    this._audioResList.push(
      ...this.data.question_arr.map((question) => {
        return question.question_audio_url;
      })
    );
    this._audioResList.push(
      ...this.data.question_arr.map((question) => {
        return question.audio_url;
      })
    );
  },

  addPreloadAnima() { },

  preload() {
    const preloadArr = [
      ...this._imageResList,
      ...this._audioResList,
      ...this._animaResList,
    ]
      .filter((url) => {
        return url;
      })
      .map((url) => {
        return {
          url: url.toLowerCase(),
        };
      });
    this.log("preload");
    cc.assetManager.loadAny(preloadArr, null, null, (err, data) => {
      if (window && window["air"]) {
        // cc.find("Canvas").opacity = 0;
        // window.air.onCourseInScreen = (next) => {
        //   cc.find("Canvas").opacity = 255;
        //   this.log("loadEnd1");
        //   this.loadEnd();
        //   next();
        // };
        // window.air.hideAirClassLoading();
        this.loadEnd();
        window["air"].hideAirClassLoading();
      } else {
        this.log("loadEnd2");
        this.loadEnd();
      }

      cc.debug.setDisplayStats(false);
    });
  },

  loadEnd() {
    this.log("loadEnd");
    this.initData();
    this.initView();
    this.initListener();
  },

  initData() {
    this.status = {
      currentQuestionIdx: 0,
      wrongTime: 0,
    };
  },

  async initView() {
    const loadingLayerBase = cc.find("Canvas/bg/loadingLayerBase");
    const loadingLayerNode = cc.instantiate(this.loadingLayerProfab);
    loadingLayerNode.name = 'loadingLayerNode';
    loadingLayerBase.addChild(loadingLayerNode);

    this.loadingLayer = loadingLayerNode.getComponent("OP32_PLUS_LoadingLayer");
    this.loadingLayer.setMaxPlayerNumber(5);

    this.loadingLayer.onLoadFinished(() => {
      this.refreshCoolCatPosition();

      this.coolCatSpeakStart(() => {
        this.startCountTime();
        this.jumpToQuestion(this.status.currentQuestionIdx);
      });
    });

    this.coolCatSpeak(this.data.startLoadingAudio);
  },

  startCountTime() {
    this._gameStartTime = new Date().getTime();
  },

  stopCountTime() {
    const duration = new Date().getTime() - this._gameStartTime;
    this.log("duration = " + (duration / 1000).toFixed(2));
    this._gameDuration = duration;
  },

  refreshCoolCatPosition() { },

  jumpToQuestion(questionIdx) {
    const questionAudioUrl = this.data.question_arr[questionIdx].audio_url;
    this.playAudioByUrl(questionAudioUrl);

    const box = cc.find("Canvas/bg/box");
    box.removeAllChildren();

    const canvasWidth = cc.find("Canvas").width;
    const canvasHeight = cc.find("Canvas").height;
    const optionNum = this.data.question_arr[questionIdx].option_arr.length;
    //TODO:copy---start
    this.hideFlower();
    const maxOptionHeight = 400;
    const maxOptionWidth = (canvasWidth * 0.8) / optionNum;
    const box_mid = cc.find('Canvas/bg/box_mid');
    box_mid.removeAllChildren();
    //TODO:copy---end

    const arr = randomSortByArr(this.data.question_arr[questionIdx].option_arr);
    arr.forEach(async (option, idx) => {
      const optionNode = await this.createOption(option);
      optionNode.name = `option_${idx}`;
      optionNode.x = (idx - (arr.length - 1) / 2) * maxOptionWidth * 1.2 - box.x;//TODO：增加部分空隙1.2倍
      optionNode.y = canvasHeight / 2 - box.y - 300;
      optionNode.scale = 0;
      optionNode.parent = box;
      optionNode.targetScale = Math.min((maxOptionWidth * 0.80) / optionNode.width, maxOptionHeight / optionNode.height)

      cc.tween(optionNode)
        .to(0.1, { scale: optionNode.targetScale })
        .start();
    });
  },

  createOption(optionData) {
    return new Promise((resolve, reject) => {
      const optionNode = cc.instantiate(cc.find("option"));
      this.loadSpriteByUrl(optionNode, optionData.pic_url, () => {
        resolve(optionNode);
      });
      optionNode.optionData = optionData;
      optionNode.optionData.selected = false;

      const box = cc.find("Canvas/bg/box");
      console.log('optionNode.on(cc.Node.EventType.TOUCH_START, (event) => {')
      optionNode.on(cc.Node.EventType.TOUCH_START, (event) => {
        if (optionNode.optionData.selected) {
          return;
        }
        const location = event.getLocation();
        optionNode.startLocation = location;
        optionNode.startPos = {
          x: optionNode.x,
          y: optionNode.y,
        };

        const selectedNum = box.children.filter(
          (child) => child.optionData.selected == true
        ).length;
        optionNode.zIndex = selectedNum;

        this.optionJump(optionNode);
        this.playAudioByUrl(optionNode.optionData.audio_url);
      });
      console.log('optionNode.on(cc.Node.EventType.TOUCH_MOVE, (event) => {')
      optionNode.on(cc.Node.EventType.TOUCH_MOVE, (event) => {
        if (optionNode.optionData.selected) {
          return;
        }
        const location = event.getLocation();
        optionNode.x =
          optionNode.startPos.x + (location.x - optionNode.startLocation.x);
        optionNode.y =
          optionNode.startPos.y + (location.y - optionNode.startLocation.y);
      });
      console.log('optionNode.on(cc.Node.EventType.TOUCH_END, (event) => {')
      optionNode.on(cc.Node.EventType.TOUCH_END, (event) => {
        if (optionNode.optionData.selected) {
          return;
        }
        const rectOption = optionNode.getBoundingBox();
        if (!cc.Intersection.rectRect(box, rectOption)) {
          cc.tween(optionNode)
            .to(
              0.05,
              {
                x: optionNode.startPos.x,
                y: optionNode.startPos.y,
              },
              cc.easing.quadOut
            )
            .start();

          this.playEffect("flyBack");
          return;
        }

        //copy-start  把物品的父节点换到中间的box上。
        const box_mid = cc.find('Canvas/bg/box_mid');
        cc.tween(optionNode).to(0.2, { x: 0, y: 420 }, cc.easing.quadOut).call(() => {
          optionNode.parent = box_mid;
        }).to(0.2, { x: 0, y: 100, scale: 0.6 }, cc.easing.quadOut).start();
        //copy-end


        this.boxJump();

        optionNode.optionData.selected = true;
      });

      return optionNode;
    });
  },

  optionJump(node, time = 0.1) {
    if (node.baseScale) {
      return;
    }
    node.baseScale = node.scaleX;

    cc.tween(node)
      .to(time, { scaleX: node.baseScale * 1.1, scaleY: node.baseScale * 1.1 })
      .to(time, { scaleX: node.baseScale * 1, scaleY: node.baseScale * 1 })
      .call(() => {
        node.baseScale = null;
      })
      .start();
  },

  initListener() {
    this.log("initListener");
    const btnSubmit = cc.find("Canvas/bg/btnSubmit");
    console.log('btnSubmit.on("click", () => {');
    btnSubmit.on("click", () => {
      this.optionJump(btnSubmit, 0.05);
      this.playEffect("submit");
      const box = cc.find("Canvas/bg/box");
      const box_mid = cc.find('Canvas/bg/box_mid');
      let children = box.children.concat(box_mid.children);
      if (children.every(
        (child) => child.optionData.selected == child.optionData.is_right
      )
      ) {
        this.onAnswerRight();
      } else {
        this.coolCatSpeakWrong(() => {
          this.status.wrongTime++;
          if (this.status.wrongTime < this.data.maxWrongNumber) {
            this.onAnswerWrong();
          } else {
            this.onAnswerWrongTwice();
          }
        });
      }
    });

    const btnNext = cc.find("Canvas/bg/btnNext");
    console.log('btnNext.on("click", () => {')
    btnNext.on("click", () => {
      this.optionJump(btnNext, 0.05);
    });

    this.initNetworkListener();
  },

  server: null,
  isRoomOwner: null,
  playerId: null,
  networkHelper: null,
  async initNetworkListener() {
    this.log("initNetworkListener");
    this.networkHelper = new NetworkHelper();

    console.log('this.networkHelper.on("playerJoin", (event) => {');
    this.networkHelper.on("playerJoin", (event) => {
      if (this.server) {
        this.server.onPlayerJoin({ data: { joinPlayerId: event.playerId } });
      }
      cc.log("playerJoin" + JSON.stringify(event));
    });
    console.log('this.networkHelper.on("playerLeave", (event) => {');
    this.networkHelper.on("playerLeave", (event) => {
      cc.log("playerLeave" + JSON.stringify(event));
    });
    console.log('this.networkHelper.on("playerOffLine", (event) => {');
    this.networkHelper.on("playerOffLine", (event) => {
      cc.log("playerOffLine" + JSON.stringify(event));
      cc.find('Canvas/PlayerOffLineLayer').active = true;
      this.networkHelper.leaveRoom();
    });
    console.log('this.networkHelper.on("gameStart", (event) => {');
    this.networkHelper.on("gameStart", (event) => { });
    console.log('this.networkHelper.on("frameEvent", (event) => {');
    this.networkHelper.on("frameEvent", (event) => {
      event.data.frame.items.forEach((item) => {
        if (this.server) {
          this.server.onFrameEvent(item.data);
        }
        if (item.data.type == "all_player_info") {
          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,
                headUrl: player.headUrl,
              });
            }
            const loadingLayerNode = cc.find('Canvas/bg/loadingLayerBase/loadingLayerNode');
            const loadingLayer = loadingLayerNode.getComponent("OP32_PLUS_LoadingLayer")
            loadingLayer.addPlayer(
              player.name,
              player.uuid == this.playerId,
              player.headUrl,
              player.uuid
            );
          });
        } else if (item.data.type == "player_complete") {
          this.log("player_complete");
          const resultNode = cc.find("resultNode");
          const resultLayer = resultNode.getComponent("OP32_PLUS_resultLayer");
          item.data.playerData.forEach((player) => {
            if (player.complete) {
              resultLayer.addPlayerResult(
                player.headUrl,
                player.uuid == this.playerId,
                player.name,
                player.duration,
                player.uuid
              );
            }
          });
          if (item.data.playerData.find(player => player.uuid == this.playerId && player.complete)) {
            item.data.playerData.sort((a, b) => {
              return a.duration - b.duration;
            });
            const idx = item.data.playerData.findIndex(player => player.uuid == this.playerId);
            this.onHomeworkFinish({
              rank: idx + 1,
              duration: this._gameDuration
            });
          }
        }
      });
    });

    try {
      this.log("喵喵喵1");
      this.playerId = await this.networkHelper.init("OP32_PLUS", 5);
      this.log("喵喵喵2");
      const room = this.networkHelper.room;
      if (this.playerId == room.roomInfo.owner) {
        this.log("房主");
        this.isRoomOwner = true;
        this.server = new GameServer(5, this.networkHelper);
        await this.networkHelper.startFrameSync();
        this.server.addPlayer({
          uuid: this.playerId,
          isAI: false,
        });
        this.server.startMatch();
      }
    } catch (e) {
      this.log(e.toString());
    }
    await this.initHeadImgAndName();
  },

  async initHeadImgAndName() {
    const playerInfo = {
      playerHeadUrl: "http://staging-teach.cdn.ireadabc.com/0751c28419a0e8ffb1f0e84435b081ce.png",
      playerName: "test",
    };
    const middleLayer = cc.find("middleLayer");
    if (middleLayer) {
      const middleLayerComponent = middleLayer.getComponent("middleLayer");
      if (middleLayerComponent.getUserInfo && middleLayerComponent.getHeadUrl) {
        const kidInfo = await middleLayerComponent.getUserInfo();
        const playerHeadUrl = middleLayerComponent.getHeadUrl(kidInfo.avatar_url || kidInfo.id);
        playerInfo.playerHeadUrl = playerHeadUrl;
        playerInfo.playerName = kidInfo.nick_name || '拼读达人';
      }
    }
    this.networkHelper.sendFrame({
      type: "playerInfo",
      playerId: this.playerId,
      playerName: playerInfo.playerName,
      playerHeadUrl: playerInfo.playerHeadUrl,
    });
  },

  //TODO:copy---start
  showFlower() {
    const flower = cc.find('Canvas/bg/烟花_ske');
    const db = flower.getComponent(dragonBones.ArmatureDisplay)
    db.playAnimation("normal", 1)
    flower.active = true;
  },
  hideFlower() {
    const flower = cc.find('Canvas/bg/烟花_ske');
    flower.active = false;
  },
  //TODO:copy---end

  finish: false,
  onHomeworkFinish(data) {
    if (!this.finish) {
      onHomeworkFinish(data);
      this.finish = true;
    }
  },

  onAnswerRight() {
    //TODO:copy---放烟花时机修改
    this.showFlower();

    this.coolCatSpeakRight(() => {
      //TODO:copy
      setTimeout(() => {
        this.nextQuestion();
      }, 1000);
    });
  },

  onAnswerWrong() {
    const box = cc.find("Canvas/bg/box");
    box.children
      .filter((child) => child.optionData.selected)
      .forEach((child) => {
        child.optionData.selected = false;
        cc.tween(child)
          .to(0.2, { x: child.startPos.x, y: child.startPos.y, scale: child.targetScale })
          .start();
      });

    //copy-start  把物品的父节点换到中间的box上。
    const box_mid = cc.find('Canvas/bg/box_mid');
    box_mid.children
      .filter(child => child.optionData.selected)
      .forEach(child => {
        child.optionData.selected = false;
        cc.tween(child)
          .to(0.2, { x: child.startPos.x, y: child.startPos.y, scale: child.targetScale })
          .call(() => {
            child.parent = box;
          })
          .start();
      });
    //copy-end

    this.playEffect("flyBackAll");
  },

  onAnswerWrongTwice() {
    this.status.currentQuestionIdx = this.data.question_arr.length;
    this.nextQuestion();
    this.playEffect("jumpAll");
  },

  nextQuestion() {
    const box = cc.find("Canvas/bg/box");
    box.children.forEach((child) => {
      cc.tween(child).to(0.1, { scaleX: 0, scaleY: 0 }).removeSelf().start();
    });
    this.status.currentQuestionIdx++;

    if (this.status.currentQuestionIdx < this.data.question_arr.length) {
      this._timeoutIds.push(
        setTimeout(() => {
          this.jumpToQuestion(this.status.currentQuestionIdx);
        }, 0.1 * 1000)
      );
    } else {
      this.coolCatSpeakEnd(() => {
        this.submitBtnMoveOut();
        this.showNextBtn();
        this.stopCountTime();
        this.showResultLayer();
        this.sendServerData();
      });
    }
  },

  sendServerData() {
    this.networkHelper.sendFrame({
      type: "complete",
      duration: this._gameDuration,
      uuid: this.playerId,
    });
  },

  showResultLayer() {
    const resultNode = cc.find("resultNode");
    resultNode.active = true;
    const resultLayer = resultNode.getComponent("OP32_PLUS_resultLayer");
    resultLayer.setFinishAudioList(this.data.finishAudioList);
  },

  boxJump() {
    const boxBehind = cc.find("Canvas/bg/box_behind");
    const boxFront = cc.find("Canvas/bg/box_front");

    this.playEffect("boxJump");

    cc.tween(boxFront)
      .to(0.1, { scaleX: 1.02, scaleY: 1.02 })
      .to(0.1, { scaleX: 1.0, scaleY: 1.0 })
      .start();
    cc.tween(boxBehind)
      .to(0.1, { scaleX: 1.02, scaleY: 1.02 })
      .to(0.1, { scaleX: 1.0, scaleY: 1.0 })
      .start();
  },

  submitBtnMoveOut() {
    const submitBtn = cc.find("Canvas/bg/btnSubmit");
    cc.tween(submitBtn).by(1, { y: -submitBtn.height }).start();
  },

  showNextBtn() {
    const btnNext = cc.find("Canvas/bg/btnNext");
    btnNext.active = true;
  },

  coolCatSpeak(url, cb) {
    const cat = cc.find("Canvas/bg/catFrame/CoolCat");
    playDragonBoneAnimation(cat, "begin", -1);
    this.playAudioByUrl(url, () => {
      playDragonBoneAnimation(cat, "normal", -1);
      if (cb) {
        cb();
      }
    });
  },

  coolCatSpeakStart(cb) {
    const cat = cc.find("Canvas/bg/catFrame/CoolCat");
    playDragonBoneAnimation(cat, "begin", -1);
    this.playAudioByUrl(this.data.startAudio, () => {
      playDragonBoneAnimation(cat, "normal", -1);
      if (cb) {
        cb();
      }
    });
  },

  coolCatSpeakRight(cb) {
    const cat = cc.find("Canvas/bg/catFrame/CoolCat");
    playDragonBoneAnimation(cat, "right", -1);
    this.playEffect("CoolCatRight", () => {
      playDragonBoneAnimation(cat, "normal", -1);
      cb();
    });
  },

  coolCatSpeakWrong(cb) {
    const cat = cc.find("Canvas/bg/catFrame/CoolCat");
    playDragonBoneAnimation(cat, "wrong", -1);
    this.playEffect("CoolCatWrong", () => {
      playDragonBoneAnimation(cat, "normal", -1);
      if (cb) {
        cb();
      }
    });
  },

  coolCatSpeakEnd(cb) {
    const cat = cc.find("Canvas/bg/catFrame/CoolCat");
    playDragonBoneAnimation(cat, "finish", -1);
    this.playAudioByUrl(this.data.endAudio, () => {
      playDragonBoneAnimation(cat, "normal", -1);
      if (cb) {
        cb();
      }
    });
  },

  // ------------------------------------------------
  loadSpriteByUrl(node, url, cb) {
    cc.loader.load(
      {
        url: url.toLowerCase(),
      },
      (err, img) => {
        if (!node) {
          cb && cb();
        }
        const spriteFrame = new cc.SpriteFrame(img);
        const spr = node.getComponent(cc.Sprite);
        spr.spriteFrame = spriteFrame;
        if (cb) {
          cb();
        }
      }
    );
  },

  currentPlayedAudioId: null,
  stopCurrentPlayedAudio() {
    if (this.currentPlayedAudioId !== null) {
      cc.audioEngine.stop(this.currentPlayedAudioId);
      this.currentPlayedAudioId = null;
    }
  },
  playEffect(name, cb) {
    this.stopCurrentPlayedAudio();
    const audioNode = cc.find(`audios/${name}`);
    const audioClip = audioNode.getComponent(cc.AudioSource).clip;
    const audioId = cc.audioEngine.play(audioClip, false, 0.8);
    this.currentPlayedAudioId = audioId;
    if (cb) {
      cc.audioEngine.setFinishCallback(audioId, cb);
    }
  },
  playAudioByUrl(audio_url, cb = null) {
    if (!audio_url) {
      if (cb) {
        cb();
      }
      return;
    }
    this.stopCurrentPlayedAudio();

    const url = audio_url.toLowerCase();

    cc.assetManager.loadRemote(url, (err, audioClip) => {
      const audioId = cc.audioEngine.play(audioClip, false, 0.8);
      this.currentPlayedAudioId = audioId;
      if (cb) {
        cc.audioEngine.setFinishCallback(audioId, cb);
      }
    });
  },

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

    this.networkHelper.onDestroy();
  },

  log(str) {
    const node = cc.find("middleLayer");
    if (node) {
      node.getComponent("middleLayer").log(str);
    } else {
      cc.log(str);
    }
  },
});
