import { asyncDelay, onHomeworkFinish, playDragonBoneAnimation, RandomInt } from "../script/util";
import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";
import Game, { FISH_OUT, GAME_STATE, Option } from "./tool/Game_op68_plus_new";
import pg from "./tool/pg_op68_plus_new";
import op68_plus_ResultLayer from "./op68_plus_new_ResultLayer";
import { NetworkHelper } from "./NetworkHelper_op68_plus_new";
import op_68_plus_LoadingLayer from "../prefab/LoadingLayer/op68_plus_new_LoadingLayer";
import { GameServer } from "./server_op68_plus_new";

const { ccclass, property } = cc._decorator;

export function getDegree(p1, p2) {
    let vector = p2.sub(p1);
    let degree = Math.atan(vector.y / vector.x) / Math.PI * 180;
    if (vector.x >= 0) {
        if (vector.y < 0) {
            degree += 360;
        }
    } else {
        if (vector.y > 0) {
            degree += 180;
        } else {
            degree = 180 + degree;
        }
    }
    return -(-degree + 90);//角度计算方法
}

let win: any = window;
let courseware = win.courseware;
enum GUN_STATE {
    WAIT = 1,
    SHUT_MIDDLE,
    SHUT_LEFT,
    SHUT_RIGHT
}
enum FISH_STATE {
    NORMAL = 1,
    BREAK,
    FALL,
}
enum TIPS_STATE {
    GOOD = 1,
    TRY,
    COM,
}
@ccclass
export default class SceneComponent extends MyCocosSceneComponent {

    addPreloadImage() {
        // TODO 根据自己的配置预加载图片资源
        this._imageResList.push(...this.data.questions.map(question => {
            return { url: question.image };
        }));
    }

    addPreloadAudio() {
        // TODO 根据自己的配置预加载音频资源
        this._audioResList.push({ url: this.data.questionTextAudio });
        this._audioResList.push({ url: this.data.bgAudio });
        this._audioResList.push(...this.data.questions.map(question => {
            return { url: question.audio };
        }));
    }

    addPreloadAnima() {

    }

    @property(cc.Node)
    spt_car: cc.Node = null;
    @property(cc.Node)
    loadingLayer: cc.Node = null;
    @property(cc.Node)
    dbCat: cc.Node = null;
    @property(cc.Node)
    item_1: cc.Node = null;
    @property(cc.Node)
    item_2: cc.Node = null;
    @property(cc.Node)
    item_3: cc.Node = null;
    @property(cc.Node)
    layout_Answer: cc.Node = null;
    @property(cc.Node)
    layout_game: cc.Node = null;

    onLoadEnd() {
        cc.macro.ENABLE_MULTI_TOUCH = false;//禁用多指操作
        // TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考

        cc.audioEngine.stopAllEffects();
        this.loadingLayer.active = true;
        let loading = this.loadingLayer.getComponent(op_68_plus_LoadingLayer);
        loading.setMaxPlayerNumber(5);
        this.initNetworkListener();
        this.initData();
        this.catPlayAni(Game.getIns().loadingAudio);
        this.dbCat.setPosition(96, 40);
        loading.onLoadFinished(() => {
            this.dbCat.setPosition(41, 395);
            this.initView();
            this.initEvent();
        });
    }
    protected onDestroy(): void {
        pg.event.clear();
    }

    initData() {
        Game.getIns().init(this.data);
        Game.getIns().reset();
        // 所有全局变量 默认都是null 
    }
    private audioId: any;
    async initView() {
        this.catPlayAni(Game.getIns().beginAudio, () => {
            this.startCountTime();
            this.gameStart();
        })
    }
    initEvent() {

    }

    private gameOver() {
        Game.getIns().state = GAME_STATE.OVER;
        this.dbCat.active = false;
        // let data: any = {};
        // data.total = Game.getIns().total;
        // data.right = Game.getIns().player.right;
        // data.scores = Game.getIns().player.voices;
        // data.stone = Math.floor(10 * data.right / data.total);
        // this.log("total: " + data.total + "      right: " + data.right + "   stone: " + data.stone);
        // onHomeworkFinish(data)
        let leaf_ske = cc.find("leaf_ske", this.node);
        leaf_ske.active = true;
        playDragonBoneAnimation(leaf_ske, "normal", 1);
        this.catPlayAni(Game.getIns().endAudio, () => {
            this.stopCountTime();
            this.sendServerData();
            this.showResultLayer();
        })
    }

    private gameStart() {
        Game.getIns().state = GAME_STATE.RUNNING;
        this.dbCat.active = true;
        this.isClick = true;
        this.initGameData();
        this.showQuestion();
        pg.audio.playAudioByUrl(Game.getIns().getCurrentPage().audio);
    }
    private questions;
    private cardInfo;
    private initGameData() {
        this.questions = [];
        let question = Game.getIns().getCurrentPage();
        for (let i = 0; i < question.optionList.length; i++) {
            this.questions[i] = question.optionList[i];
        }
    }

    private showQuestion(show = true) {
        let question = Game.getIns().getCurrentPage();
        let car = cc.instantiate(this.spt_car);
        let layout_item = cc.find("layout_item", car);
        layout_item.removeAllChildren();
        question.group_arr.forEach((data, idx) => {
            let item = cc.instantiate(this.item_1);
            layout_item.addChild(item);
            item.active = true;
            let title = cc.find("title", item);
            title.getComponent(cc.Label).string = data.text;
            title.active = question.type == "img";
            item.idx = idx + 1;
            let btnAudio = cc.find("btnAudio", item);
            btnAudio.active = question.type == "txt";
            btnAudio.on(cc.Node.EventType.TOUCH_END, () => {
                pg.audio.playAudioByUrl(data.audio);
            }, this);
        })
        car.parent = this.layout_game;
        car.x = 1500;
        car.active = true;
        layout_item.getComponent(cc.Layout).updateLayout();
        if (layout_item.children.length > 2) {
            let scale = layout_item.children.length == 3 ? 0.8 : 0.6;
            layout_item.children.forEach((ch) => {
                ch.scale = scale;
            })
        }

        if (question.page > 1) {
            let c0 = this.layout_game.children[0];
            cc.tween(c0).to(1.5, { x: -1500 }).call(() => {
                c0.parent = null;
                c0.destroy();
            }).start();
        }
        cc.tween(car).to(1.5, { x: 0 }).call(() => {
            this.onNext();
        }).start();

    }
    private showOption() {
        let question = Game.getIns().getCurrentPage();
        if (question.type == "txt") {
            let item = cc.instantiate(this.item_3);
            let answer_4 = cc.find("answer_4", item);
            let word = cc.find("word", answer_4);
            word.getComponent(cc.Label).string = this.cardInfo.txt;
            item.parent = this.layout_Answer;
            answer_4.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
            answer_4.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            answer_4.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
            answer_4.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
            item.y = 0;
            item.x = 1700;
            item.active = true;
            cc.tween(item).to(0.6, { x: 0 }).start();
        } else {
            let item = cc.instantiate(this.item_2);
            item.parent = this.layout_Answer;
            let pic = cc.find("pic", item);
            pg.view.setNetImg(pic, this.cardInfo.picUrl, { w: 110, h: 114 });
            pic.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
            pic.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            pic.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
            pic.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
            item.y = 0;
            item.x = 1700;
            item.active = true;
            cc.tween(item).to(0.6, { x: 0 }).start();
        }

    }
    private onTouchCancel(e) {
        if (!this.isClick || !this.touching) return;
        let target: cc.Node = e.target;
        let question = Game.getIns().getCurrentPage();
        this.playWrongAudio();
        let name = question.type == "txt" ? "item_3" : "item_2";
        let card = cc.find(name, this.layout_Answer);
        target.parent = card;
        target.setSiblingIndex(question.type == "txt" ? 0 : 5);
        target.setPosition(0, 0);
    }
    private isClick;
    private touching;
    private onTouchStart(e) {
        if (!this.isClick || this.touching) return;
        this.touching = true;
        let target: cc.Node = e.target;
        target.parent = this.node;
        this.setTouchPos(e);

    }
    private onTouchMove(e) {
        if (!this.isClick || !this.touching) return;
        let target: cc.Node = e.target;
        this.setTouchPos(e);

    }
    private onTouchEnd(e) {
        if (!this.isClick || !this.touching) return;
        this.touching = false;
        let target: cc.Node = e.target;
        let car = cc.find("spt_car/layout_item", this.layout_game);
        if (!car) return;
        let item: any = car.children.find((ch) => {
            let dis = this.getDistances(target, ch);
            if (dis < 195) {
                return ch;
            }
            return null;
        })
        let question = Game.getIns().getCurrentPage();
        let name = question.type == "txt" ? "item_3" : "item_2";
        let card = cc.find(name, this.layout_Answer);
        if (!item || item.idx != this.cardInfo.id) {
            this.playWrongAudio();
            target.parent = card;
            target.setSiblingIndex(question.type == "txt" ? 0 : 5);
            target.setPosition(0, 0);
            return;
        }
        this.playLocalAudio("right");
        if (question.type == "txt") {
            this.addTxteImg(item);
            cc.tween(target).to(0.5, { scale: 1.2 }).to(0.2, { scale: 0.5 }).call(() => {
                this.wordRight(item).then(() => {
                    this.hideTop(card);
                });
                target.parent = null;
                target.destroy();
            }).start();
        } else {
            this.picRight(item, target);
            this.wordRight(item).then(() => {
                this.hideTop(card);
            });
        }
        this.isClick = true;
    }
    private hideTop(item) {
        cc.tween(item).to(0.5, { x: -1700 }).call(() => {
            this.onNext();
        }).start();
    }

    private addTxteImg(item) {
        let node = new cc.Node();
        node.addComponent(cc.Sprite);
        pg.view.setNetImg(node, this.cardInfo.picUrl, { w: 110, h: 114 });
        let layout_img = cc.find("layout_img", item);
        node.parent = layout_img;
        let scale = layout_img.parent.scale
        node.scale = scale < 0.9 ? 0.9 : scale;
    }
    private wordRight(item) {
        return new Promise((resolve, reject) => {
            let layout_word = cc.find("layout_word", item);
            let labText = cc.instantiate(cc.find("labText", item));
            labText.getComponent(cc.Label).string = this.cardInfo.txt;
            labText.active = true;
            labText.parent = layout_word;
            cc.tween(labText).to(0.2, { scale: 1.5 }).to(0.5, { scale: 1 }).call(() => {
                // labText.parent = layout_word;
                return resolve("");
            }).start();
        });
    }
    private picRight(item, pic) {
        return new Promise((resolve, reject) => {
            let layout_img = cc.find("layout_img", item);
            pic.parent = layout_img;
            pic.setPosition(0, 0);
            pic.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
            pic.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
            pic.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
            return resolve("");
        });
    }

    private playWrongAudio() {
        this.isClick = false;
        let random = Math.floor(Math.random() * 3);
        playDragonBoneAnimation(this.dbCat, "begin", -1);
        this.playLocalAudio("wrong" + random).then(() => {
            playDragonBoneAnimation(this.dbCat, "normal", -1);
            this.isClick = true;
        });
    }


    private onNext() {
        this.getCardInfo();
        if (!this.cardInfo) {
            console.log("over");
            pg.audio.playAudioByUrl(Game.getIns().getCurrentPage().endAudio).then(() => {
                this.checkRoundEnd();
            });
            return;
        }
        this.layout_Answer.removeAllChildren();
        this.showOption();
    }
    private getCardInfo() {
        if (this.questions.length > 0) {
            let random = Math.floor(Math.random() * this.questions.length);
            this.cardInfo = this.questions.splice(random, 1)[0];
        } else {
            this.cardInfo = null;
        }
        console.log(" this.cardInfo=======", this.cardInfo)
    }
    //根据两点获取距离
    private getDistance(p1, p2) {
        let temp = p1.sub(p2);
        let dis = Math.abs(temp.mag());
        return dis;
    }
    private getDistances(p1, p2) {
        //转换世界坐标查看距离
        let ps2 = p2.convertToWorldSpaceAR(cc.v2(0, 0));
        let ps1 = p1.convertToWorldSpaceAR(cc.v2(0, 0));
        let temp = ps1.sub(ps2);
        let dis = Math.abs(temp.mag());
        return dis;
    }
    private count: number;
    update(dt) {
        if (Game.getIns().state != GAME_STATE.RUNNING) return;
        // if (this.touching) return;
    }

    private catPlayAni(url, cb = null) {
        playDragonBoneAnimation(this.dbCat, "begin", -1);
        pg.audio.playAudioByUrl(url).then(() => {
            playDragonBoneAnimation(this.dbCat, "normal", -1);
            if (cb) {
                cb();
            }
        })
    }

    private checkRoundEnd() {
        Game.getIns().addPage();
        if (!Game.getIns().getCurrentPage()) {
            this.gameOver();
        } else {
            this.gameStart();
        }

    }



    private setTouchPos(e) {
        let location = e.getLocation();
        let size = cc.view.getCanvasSize();
        let scale = (size.width / size.height) / (1280 / 720);
        if (scale > 1) {
            let width = size.width / size.height * 720;
            let pos = location.sub(cc.v2(width / 2, 720 / 2))
            e.target.setPosition(pos)
        } else {
            let height = size.height / size.width * 1280;
            let pos = location.sub(cc.v2(1280 / 2, height / 2))
            e.target.setPosition(pos)
        }
    }


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

    async showOneFirework(pos, parentNode, nodeList) {

        for (let i = 0; i < 3; i++) {
            this.showFirework(pos, parentNode, nodeList, 200, 200, 25);
            await asyncDelay(0.1);
        }
    }

    showFirework(pos, parentNode, nodeList, width = 200, height = 500, number = 30) {
        for (let i = 0; i < number; i++) {
            const quad = this.createQuads(pos, parentNode, nodeList);
            const targetX = RandomInt(width / 2, -width / 2);
            const targetY = RandomInt(height);

            cc.tween(quad)
                .by(0.5, { x: targetX })
                .by(3, { x: targetX * 2 })
                .start();

            cc.tween(quad)
                .by(0.5, { y: targetY }, { easing: 'quadOut' })
                .to(4, { y: -parentNode.height * 2 }, { easing: 'quadIn' })
                .removeSelf()
                .start();

            cc.tween(quad)
                .delay(1)
                .to(0.5 + 1 * Math.random(), { opacity: 0 })
                .start();
        }
    }

    createQuads(pos, parentNode, nodeList) {
        const quadBase = cc.instantiate(nodeList[RandomInt(nodeList.length)]);
        // console.log('nodeList', nodeList);
        // console.log('quadBase', quadBase);
        quadBase.x = pos.x;
        quadBase.y = pos.y + 30;
        quadBase.z = pos.z;
        quadBase.angle = RandomInt(180);
        quadBase.parent = parentNode;

        const quad = quadBase.getChildByName('quad');
        quad.x = 0;
        quad.y = 0;
        quad.angle = RandomInt(180);

        const paper = quad.getChildByName('paper');
        paper.scaleX = Math.random() * 0.8 + 0.2;
        paper.scaleY = Math.random() * 0.8 + 0.2;

        quadBase.scaleX = Math.random();
        cc.tween(quadBase)
            .to((1 - quadBase.scaleX) * 0.3, { scaleX: 1 })
            .call(() => {
                const time = Math.random() * 0.2;
                cc.tween(quadBase)
                    .to(0.1 + time, { scaleX: -1 })
                    .to(0.1 + time, { scaleX: 1 })
                    .union()
                    .repeatForever()
                    .start();
            })
            .start();


        return quadBase;
    }




















    private _gameStartTime: number;
    private _gameDuration: number;

    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(op68_plus_ResultLayer);
        resultLayer.setFinishAudioList(Game.getIns().finishAudioList);
    }

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

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

        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));
        });
        this.networkHelper.on("playerOffLine", (event) => {
            cc.log("playerOffLine" + JSON.stringify(event));
            cc.find("Canvas/PlayerOffLineLayer").active = true;
            this.networkHelper.leaveRoom();
        });
        this.networkHelper.on("gameStart", (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,
                            });
                        }

                        this.loadingLayer.getComponent(op_68_plus_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(op68_plus_ResultLayer);
                    item.data.playerData.sort((a, b) => {
                        return a.duration - b.duration;
                    });
                    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
                        });
                    }
                }
            });
        });

        do {
            this.playerId = await this.networkHelper.init("op_09_plus", 5);
            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) {
            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();
        }
        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,
        });
    }

    finish: boolean;
    onHomeworkFinish(data) {
        if (!this.finish) {
            onHomeworkFinish(data);
            this.finish = true;
        }
    }
    startCountTime() {
        this._gameStartTime = new Date().getTime();
    }

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


}

