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

const { ccclass, property } = cc._decorator;

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

    @property(cc.Node)
    cover = null

    _cardList: Array<cc.Node> = [];
    private _isRolling: any;

    _randomList = ["1", "2", "3"]
    excellent: any;
    _nowData: any;
    private _nextIdx: any;
    private _nowIndex: number;
    private _nowIdx: number;
    private _myData: any;
    private _myLastPos: cc.Vec2;
    private _otherLastPos: cc.Vec2;
    private _loadingDone: boolean = false;


    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 = {
        state: -1,// -1:未开始 0 准备阶段  1 roll 2 判定
        Red: -1,
        Blue: -1,
        step: 0,
        current: "Blue",
        jump: null
    };
    playerId;
    isRoomOwner;
    server: GameServer;
    networkHelper: NetworkHelper;
    async initData() {
        this.initCards();

        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();
            this.server.randomList = this._randomList;
            this.server.TotalStep = this._cardList.length;
            await this.networkHelper.startFrameSync();
            this.server.addPlayer({
                uuid: this.playerId,
                isAI: false,
            });
            this.server.startMatch();
        }
        await this.initHeadImgAndName();
    }

    async initHeadImgAndName() {
        const playerInfo: any = {
            playerHeadUrl: "http://staging-teach.cdn.ireadabc.com/0751c28419a0e8ffb1f0e84435b081ce.png",
            playerName: "test",
        };
        const middleLayer = cc.find("middleLayer");
        if (middleLayer) {

            const middleLayerComponent = middleLayer.getComponent("middleLayer");
            middleLayerComponent.log("这里 打log?");
            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,
        });
    }

    initCards() {

        let cardDatas = [
            {
                id: 1, rJumpId: 2, wJumpId: null, word: "bat", url: "",
            },
            {
                id: 2, rJumpId: 3, wJumpId: null, word: "man", url: "",
            },
            {
                id: 3, rJumpId: 4, wJumpId: null, word: "pad", url: "",
            },
            {
                id: 4, rJumpId: 5, wJumpId: null, word: "dam", url: "",
            },
            {
                id: 5, rJumpId: 6, wJumpId: null, word: "map", url: "",
            },
            {
                id: 6, rJumpId: 7, wJumpId: null, word: "ant", url: "",
            },
            {
                id: 7, rJumpId: 8, wJumpId: null, word: "can", url: "",
            },
            {
                id: 8, rJumpId: 9, wJumpId: null, word: "cam", url: "",
            },
            {
                id: 9, rJumpId: 10, wJumpId: null, word: "mat", url: "",
            },
            {
                id: 10, rJumpId: 11, wJumpId: null, word: "cat", url: "",
            },
            {
                id: 11, rJumpId: 12, wJumpId: null, word: "fan", url: "",
            },
            {
                id: 12, rJumpId: 13, wJumpId: null, word: "tap", url: "",
            },
            {
                id: 13, rJumpId: 14, wJumpId: null, word: "cap", url: "",
            },
            {
                id: 14, rJumpId: 15, wJumpId: null, word: "bag", url: "",
            },
            {
                id: 15, rJumpId: 16, wJumpId: null, word: "yam", url: "",
            },
            {
                id: 16, rJumpId: 17, wJumpId: null, word: "yak", url: "",
            },
            {
                id: 17, rJumpId: 18, wJumpId: null, word: "rat", url: "",
            },
            {
                id: 18, rJumpId: 19, wJumpId: null, word: "rag", url: "",
            },
            {
                id: 19, rJumpId: 20, wJumpId: null, word: "pan", url: "",
            },
            {
                id: 20, rJumpId: 21, wJumpId: null, word: "dad", url: "",
            },
            {
                id: 21, rJumpId: 22, wJumpId: null, word: "jam", url: "",
            },
            {
                id: 22, rJumpId: 23, wJumpId: null, word: "ax", url: "",
            },
            {
                id: 23, rJumpId: 24, wJumpId: null, word: "hat", url: "",
            },
            {
                id: 24, rJumpId: null, wJumpId: null, word: "map", url: "",
            },

        ]
        this._cardList = cc.find("Canvas/road/root/wordCards").children;
        let list = this.data.cardDatas || cardDatas;
        for (let i = 0; i < this._cardList.length; ++i) {
            let data = list[i];
            let com = this._cardList[i].addComponent(BoardCardItem);
            com.cardData = data;
        }
    }
    initView() {
        this.initBg();
        this.initLoadingLayer();
        this.initPiece();
    }

    getJumpList() {
        const jumpList = [];
        this._cardList.forEach(node => {
            const itemData = node.getComponent(BoardCardItem);
            if (itemData.rjumpId) {
                const from = itemData.Id;
                const to = itemData.rjumpId;
                jumpList.push({ from, to });
            }
        });
        return jumpList;
    }

    initBg() {
        const bgNode = cc.find('Canvas/bg');
        bgNode.scale = this._mapScaleMax;
    }

    loadingLayer;
    initLoadingLayer() {

        const loadingLayerNode = cc.instantiate(this.loadingLayerPrefab);
        loadingLayerNode.parent = this.node;
        loadingLayerNode.zIndex = 100;

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

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

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

    normaltheDice() {

        cc.find("Canvas/road/board").children.forEach((node) => {
            node.stopAllActions();
            node.color = cc.color(250, 250, 250);
        });
    }

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



    initPiece() {

    }

    initListener() {
        this.boardBtn.on("click", () => {
            if (!this.isMySide || this._status.state != 0) {
                return;
            }
            this.networkHelper.sendFrame({
                type: "roll",
                uuid: this.myData.uuid,
            });
        });


    }


    stopRollPiece() {
        let node = this.getCurrentPiece()
        node.stopAllActions();
    }

    rollPiece() {
        let node = this.getCurrentPiece()
        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();


        this._cardList.forEach((child: cc.Node, idx, list) => {
            cc.tween(child)
                .set({ scale: 1 })
                .delay(idx * 0.1)
                .to(0.1, { scale: 1.1 })
                .to(0.1, { scale: 1 })
                .delay(list.length * 0.11 - idx * 0.11)
                .start();
        });
    }

    jumpBlock(idx) {

        const targetNode = this._cardList[idx];
        return targetNode;
    }

    getNextRightIdx() {

        const startIdx = this._status[this._status.current];
    }

    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 peaceJumpAndSpeak() {
        let node = cc.find(`Canvas/road/root/piece${this._status.current}`);
        let nowIdx = this._status[this._status.current];
        let nextIdx = nowIdx + this._status.step;
        let word = await this.pieceJump(node, nowIdx, nextIdx);
        if (this.isMySide) {
            let card = this._cardList[nextIdx];
            await this.openCoursView(card);
            await this._startCourseware(word);
        }

    }

    openCoursView(node) {
        this.cover.active = true;
        let probar = this.cover.getChildByName("probar");
        this.cover.getChildByName("bar").removeAllChildren();
        let icon = cc.instantiate(node);
        icon.parent = this.cover.getChildByName("bar");
        icon.x = 0;
        icon.y = 0;
        icon.scale = 1;

        probar.getComponent(cc.ProgressBar).unscheduleAllCallbacks();
        let total = 1;
        probar.getComponent(cc.ProgressBar).schedule(() => {
            probar.getComponent(cc.ProgressBar).progress = total;
            total -= 1 / 30;
            if (total < 0) {
                probar.getComponent(cc.ProgressBar).unscheduleAllCallbacks();
                this._coursewareStoped();
            }

        }, 0.1, 31, 0.1)
    }

    async _startCourseware(word) {

        if (!cc.sys.isBrowser && window["courseware"]?.startTest) {

            console.log("模拟录音开始 单词：" + word);
            window["courseware"]?.startTest(word);
        } else {

            console.log("web 模拟录音开始");
        }

        await asyncDelay(3);

        this._coursewareStoped();

    }
    async _coursewareStoped() {

        if (!this.cover.active) {
            return;
        }

        this.cover.active = false;
        cc.tween(this.cover).to(0.5, { opacity: 255 }).start();
        await asyncDelay(0.5);

        if (!cc.sys.isBrowser && window["courseware"]?.stopTest) {
            window["courseware"]?.stopTest((res, b) => {

                if (typeof res == "string") {
                    res = JSON.parse(res);
                }
                console.log("++++++++++++ _coursewareEnd  +++++++++++++++");
                this._coursewareEnd(res.result?.pronunciation || 0,)
                console.log("pronunciation=== " + res.result?.pronunciation);

                console.log("333=== " + res.result?.pronunciation);

            });
        } else {
            await asyncDelay(3);
            console.log("web 模拟录音评测 结果");
            this._coursewareEnd(Math.random() > 0.5 ? 100 : 70)
        }

    }
    async _coursewareEnd(score: number) {

        if (score >= 80) {

            console.log("====评测通过=====");
            this.networkHelper.sendFrame({
                type: "right",
                uuid: this.myData.uuid,
            });


        } else {

            console.log("====评测不通过=====");
            this.networkHelper.sendFrame({
                type: "wrong",
                uuid: this.myData.uuid,
            });

        }

    }


    roundEndCheck() {
        this.networkHelper.sendFrame({
            type: "stateUpdate",
            uuid: this.myData.uuid,
        });
    }

    async updateStatus(status = null) {

        if (!this._loadingDone) return;

        let state = this._status.state;

        switch (state) {
            case -1:
                break;
            case 0:
                if (this.isMySide) {
                    this.normaltheDice();
                    await this.showYourTurn();
                    this.blinkTheDice();
                } else {
                    this.greyDice();
                }

                this.rollPiece();
                break;
            case 1:
                if (this.isMySide) {

                } else {
                    this.greyDice();
                }
                this.stopRollPiece();
                break;
            case 2:
                if (this.isMySide) {

                } else {
                    this.greyDice();
                }
                break;

        }

        const blueFrame = cc.find("Canvas/road/blueHead/icon");
        const redFrame = cc.find("Canvas/road/redHead/icon");
        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/road/root/pieceRed");
        } else {
            return cc.find("Canvas/road/root/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() {

        console.log("=====showYourTurn===========");
        return new Promise((resolve, reject) => {
            const yourTurn = cc.find("Canvas/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 pieceJump(node, from, to) {
        return new Promise((resolve) => {
            if (from < to) {
                let card = this._cardList[from + 1];
                cc.tween(node).to(0.2, { position: card.position }).call(() => {
                    resolve(this.pieceJump(node, from + 1, to));
                }).start()
            } else {
                let word = this._cardList[from + 1].getComponent(BoardCardItem)._word
                resolve(word);
            }
        })
    }

    async fixStep() {
        if (this._status.jump) {
            let node = cc.find(`Canvas/road/root/piece${this._status.current}`);
            let pos = this._cardList[this._status.jump].position;
            await asyncTweenTo(
                node,
                0.7,
                { x: pos.x, y: pos.y },
                { easing: "cubicOut" }
            );
            node.stopAllActions();
        }
    }
    async pieceGoBack() {

        this.playLocalAudio("wrong");
        let node = cc.find(`Canvas/road/root/piece${this._status.current}`);

        let pos;
        if (this._status.jump) {
            pos = this._cardList[this._status.jump].position;
        } else {
            let Idx = this._status[this._status.current];
            pos = this._cardList[Idx].position;
            console.log("now idx == " + Idx);
        }

        await asyncTweenTo(
            node,
            0.7,
            { x: pos.x, y: pos.y },
            { easing: "cubicOut" }
        );
        node.stopAllActions();
    }

    get isMySide() {

        const playerMe = this.allPlayerList.find(
            (player) => player.uuid == this.playerId
        );
        return playerMe.color == this._status.current

    }
    get myData() {

        if (!this._myData) {
            const playerMe = this.allPlayerList.find(
                (player) => player.uuid == this.playerId
            );
            this._myData = playerMe;
        }

        return this._myData;
    }


    allPlayerList;
    initNetworkListener() {
        this.networkHelper.on("playerJoin", (event) => {
            if (this.server) {
                this.server.onPlayerJoin({ data: { joinPlayerId: event.playerId } });
            }
            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);
                }

                console.log("event type " + item.data.type);
                console.log("event data" + JSON.stringify(item.data.status));
                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") {
                    this._status = JSON.parse(JSON.stringify(item.data.status));
                    this.updateStatus();
                } else if (item.data.type == "SERVER_playerRoll") {
                    this._status = JSON.parse(JSON.stringify(item.data.status));
                    if (this.isMySide) {
                        this.normaltheDice();
                    } else {
                        this.greyDice();
                    }
                    await this.rollTheDice(this._status.step);
                    console.log("rollTheDice done");
                    await this.peaceJumpAndSpeak();
                    console.log("peaceJumpAndSpeak done");
                    this.roundEndCheck();
                }
                else if (item.data.type == "SERVER_playerRight") {

                    this.playLocalAudio("right");
                    this._status = JSON.parse(JSON.stringify(item.data.status));
                    await this.fixStep();
                    this.roundEndCheck();

                } else if (item.data.type == "SERVER_playerWrong") {
                    await this.pieceGoBack();
                    this.roundEndCheck();
                } else if (item.data.type == "SERVER_playerWin") {
                    this._status = JSON.parse(JSON.stringify(item.data.status));
                    const node = cc.find(
                        `Canvas/road/root/piece${this._status.current}`
                    );
                    const idx = this._cardList.length;
                    const rightBlock = this._cardList[idx - 1];
                    // await this.pieceFindRightBlock(rightBlock, idx);
                    if (this.isMySide) {
                        this.showWin();
                        onHomeworkFinish({ isWin: true });
                    } else {
                        this.showLoss();
                        onHomeworkFinish({ isWin: false });
                    }
                }
            });
        });
    }

    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/road/redHead/icon");
        const blue = cc.find("Canvas/road/blueHead/icon");
        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;

                }
            });
        });
    }



    finish() {
        // onHomeworkFinish();
    }

    rollTheDice(num) {
        if (this._isRolling) {
            return;
        }
        const dice = cc.find("Canvas/road/board/runBoard");
        return new Promise((resolve, reject) => {
            const targetAngle = Math.ceil(dice.angle / 360 + 1) * 360;
            const time = (targetAngle - 360 - dice.angle) / 360;
            this._isRolling = 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(() => {
                    this._isRolling = false;
                    resolve(null);
                })
                .start();
        });
    }

    playLocalAudio(audioName) {
        this.node.getChildByName("audio").getChildByName(audioName).getComponent(cc.AudioSource).play();
    }



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