import { asyncDelay, onHomeworkFinish } from "../script/util";
import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";
import Game, { FISH_OUT, GAME_STATE, Option } from "./tool/Game";
import pg from "./tool/pg";

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({ url: this.data.pic_url });
        this._imageResList.push({ url: this.data.pic_url_2 });
    }

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

    addPreloadAnima() {

    }

    onLoadEnd() {
        // TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考
        this.initData();
        this.initView();
        this.initEvent();
    }
    protected onDestroy(): void {
        pg.event.clear();
    }

    @property(cc.Node)
    res: cc.Node = null;
    @property(cc.Node)
    layout_player: cc.Node = null;
    @property(cc.Node)
    layout_balloon: cc.Node = null;
    @property(cc.Node)
    layout_card: cc.Node = null;
    @property(cc.Node)
    layout_speak: cc.Node = null;
    @property(cc.Node)
    layout_tip: cc.Node = null;
    @property(cc.Node)
    item_gun: cc.Node = null;

    @property(cc.Node)
    item_left: cc.Node = null;
    @property(cc.Node)
    item_right: cc.Node = null;
    _cantouch = null;
    initData() {
        Game.getIns().init(this.data);
        Game.getIns().reset();
        this.tryData = [];
        // 所有全局变量 默认都是null 
        this._cantouch = true;
    }
    private layout_start: cc.Node;
    private audioId: any;
    async initView() {
        cc.audioEngine.stopAllEffects();
        this.layout_start = pg.view.find(this, "layout_start");

        this.layout_start.active = true;
        let desc = this.layout_start.getChildByName("desc");
        desc.getComponent(cc.Label).string = Game.getIns().questionText;
        this.audioId = await pg.audio.playAudioByUrl(Game.getIns().question.audio);
        if (this.audioId > -1 && Game.getIns().state == GAME_STATE.RUNNING) {
            cc.audioEngine.stopAllEffects();
            pg.audio.stopAudio(this.audioId);
        }
    }
    initEvent() {
        pg.view.touchOn(pg.view.find(this.layout_start, 'btn_start'), this.onTouchStart, this);

        pg.event.on("game_start", () => {
            this.gameStart();
        })
        pg.event.on("game_time_over", () => {
            // alert("game_time_over")
            //这里的事件会发送的很早。但是我们需要等待动画执行完了之后再开始后续的内容
            Game.getIns().addPage();
            if (!Game.getIns().isOver) return pg.event.emit("game_start");
            //发送给上端最后的数据
            // alert("game_finish")
            // int  total  
            // int  right
            // int[]  scores   
            // let player = { right: Game.getIns().player.score, error: Game.getIns().player.error }

            let data: any = {};
            data.total = Game.getIns().player.score;
            data.right = Game.getIns().player.right;
            data.scores = Game.getIns().player.voices;
            onHomeworkFinish(data)
        })
    }
    onTouchStart() {
        pg.audio.playLocalAudio(cc.find(`Canvas/res/audio/btn`));
        pg.event.emit("game_start");
    }


    private count: number;
    private list: Option[];
    private fishs: cc.Node[];
    gameStart() {
        Game.getIns().state = GAME_STATE.RUNNING;
        this.playGun(GUN_STATE.WAIT)
        this.updateTips(null);
        //游戏开始小鱼出现等等
        this.layout_start.active = false;
        if (this.audioId > -1 && Game.getIns().state != GAME_STATE.WAIT) {
            cc.audioEngine.stopAllEffects();
            pg.audio.stopAudio(this.audioId);
        }
        //开始  

        //根据数据随机热气球
        let page = Game.getIns().getCurrentPage();
        let list = page.optionList.concat();
        list = JSON.parse(JSON.stringify(list));
        list.sort((A, B) => { return Math.random() < 0.5 });
        this.list = list;
        Game.getIns().player.addScore(this.list.length);
        this.count = 0;
        this.lastCount = null;
        this.fishs = [];
        this.viewFishs = [];
        this.touchFishs = [];
        //根据顺序生成对应的鱼。
        //顺序根据时间来进行跳动。当顺序跳动之后，就会产生新的鱼。
    }
    private lastCount: number;
    private viewFishs: Option[];
    private touchFishs: Option[];
    getFishByCount(count) {
        if (count <= this.lastCount) return null;
        if (!this.list) return;
        if (this.list.length == this.touchFishs.length) {
            Game.getIns().state = GAME_STATE.OVER;
            return pg.event.emit("game_time_over");
        }
        this.lastCount = count;
        let list = this.list.filter((li) => {
            return this.viewFishs.every(v => v.id != li.id) && this.touchFishs.every(t => t.id != li.id);
        });
        if (list.length == 0) return null;
        let data = JSON.parse(JSON.stringify(list[count % list.length]));
        data.fish.isLeft = Math.random() < 0.5;
        let item_base = data.fish.isLeft ? this.item_left : this.item_right;
        let item = cc.instantiate(item_base);
        this.updateFish(item, data);
        this.viewFishs.push(data);
        return item;
    }
    private fishCount: number;
    private lastY: number;
    updateFish(item, data: Option) {
        pg.view.touchOn(item, this.onTouchItem, this);
        if (!this.fishCount) this.fishCount = 0;
        let id = this.fishCount % 5 + 1;
        this.fishCount++;
        let res = pg.view.find(item, 'res');

        pg.view.visible(pg.view.find(item, 'img_normal'), true);
        pg.view.visible(pg.view.find(item, 'img_fall'), false);
        pg.view.visible(pg.view.find(item, 'light'), false);

        let i = Math.ceil(Math.random() * 4);
        pg.view.setNodeImg(pg.view.find(item, 'img_normal'), pg.view.find(res, `img_balloon${i}_1`));
        pg.view.setNodeImg(pg.view.find(item, 'img_fall'), pg.view.find(res, `img_balloon${i}_2`));

        item.parent = this.layout_balloon;
        item.data = data;
        data.fish.node = item;
        //x y   起始点 和终点  进行  随机
        cc.Tween.stopAllByTarget(item);
        //左往右
        item.x = -1334 / 2 + Math.random() * 1334;
        item.y = -(720 / 2 + Math.random() * 400);//
        cc.tween(item).to(7 + Math.random() * 6, { y: 1500 }).call(() => {
            data.fish.isOut = FISH_OUT.OUT;
            this.viewFishs = this.viewFishs.filter(v => v.id != data.id);
        }).start();
    }
    private touching: boolean;

    updateFishState(item: cc.Node, state: FISH_STATE) {
        return new Promise((resolve, reject) => {
            switch (state) {
                case FISH_STATE.NORMAL:
                    pg.view.visible(pg.view.find(item, 'img_normal'), true);
                    pg.view.visible(pg.view.find(item, 'img_fall'), false);
                    pg.view.visible(pg.view.find(item, 'light'), false);
                    resolve('');
                    break;
                case FISH_STATE.BREAK:
                    pg.view.visible(pg.view.find(item, 'img_normal'), true);
                    pg.view.visible(pg.view.find(item, 'img_fall'), false);
                    pg.view.visible(pg.view.find(item, 'light'), true);
                    resolve('');
                    break;
                case FISH_STATE.FALL:
                    pg.view.visible(pg.view.find(item, 'img_normal'), false);
                    pg.view.visible(pg.view.find(item, 'img_fall'), true);
                    pg.view.visible(pg.view.find(item, 'light'), false);
                    resolve('');
                    break;
            }
        });
    }

    playGun(state: GUN_STATE) {
        return new Promise((resolve, reject) => {
            let gun1 = pg.view.find(this.item_gun, 'gun1');
            let gun2 = pg.view.find(this.item_gun, 'gun2');
            let gun3 = pg.view.find(this.item_gun, 'gun3');
            let gun4 = pg.view.find(this.item_gun, 'gun4');
            let ani = null;
            switch (state) {
                case GUN_STATE.WAIT:
                    gun1.active = true;
                    gun2.active = false;
                    gun3.active = false;
                    gun4.active = false;
                    resolve('');
                    break;
                case GUN_STATE.SHUT_RIGHT:
                    this.playLocalAudio("ball")
                    gun1.active = false;
                    gun2.active = false;
                    gun3.active = false;
                    gun4.active = true;
                    ani = pg.view.playDBAnimation(gun4, 'newAnimation', 1);
                    ani.addEventListener(dragonBones.EventObject.LOOP_COMPLETE, () => {
                        this.playGun(GUN_STATE.WAIT);
                        resolve('');
                    })
                    break;
                case GUN_STATE.SHUT_LEFT:
                    this.playLocalAudio("ball")
                    gun1.active = false;
                    gun2.active = false;
                    gun3.active = true;
                    gun4.active = false;
                    ani = pg.view.playDBAnimation(gun3, 'newAnimation', 1);
                    ani.addEventListener(dragonBones.EventObject.LOOP_COMPLETE, () => {
                        this.playGun(GUN_STATE.WAIT);
                        resolve('');
                    })
                    break;
                case GUN_STATE.SHUT_MIDDLE:
                    this.playLocalAudio("ball")
                    gun1.active = false;
                    gun2.active = true;
                    gun3.active = false;
                    gun4.active = false;
                    ani = pg.view.playDBAnimation(gun2, 'newAnimation', 1);
                    ani.addEventListener(dragonBones.EventObject.LOOP_COMPLETE, () => {
                        this.playGun(GUN_STATE.WAIT);
                        resolve('');
                    })
                    break;
            }
        });
    }
    playCard(data?: Option) {
        return new Promise((resolve, reject) => {
            if (!data) {
                this.layout_card.active = false;
                return;
            }
            this.layout_card.active = true;
            let layout_txt = pg.view.find(this.layout_card, "layout_txt");
            let layout_img = pg.view.find(this.layout_card, "layout_img");
            let bg_gray = pg.view.find(this.layout_card, 'bg_gray');
            let touch = pg.view.find(this.layout_card, 'touch');
            layout_txt.active = false;
            layout_img.active = false;
            bg_gray.active = true;
            touch.active = true;
            let layout = layout_txt;
            if (data.type == "txt") {
                pg.view.setString(pg.view.find(layout_txt, 'desc'), data.txt)
            } else {
                layout = layout_img;
                pg.view.setNetImg(pg.view.find(layout_img, 'img'), data.picUrl, { w: 440, h: 286 })
            }
            touch.off(cc.Node.EventType.TOUCH_END);
            //动画效果
            this.playLocalAudio("card").then(() => {
                pg.audio.playAudioByUrl(data.audioUrl, () => {
                    touch.on(cc.Node.EventType.TOUCH_END, () => {
                        pg.audio.playAudioByUrl(data.audioUrl);
                    })
                });
            })

            layout.active = true;
            layout.opacity = 255;
            layout.scale = 0.1;
            cc.tween(layout).to(0.5, { scale: 1.1 }).to(0.06, { scale: 1 }).call(() => {
                resolve('');
            }).start();
        });
    }

    fishingRight(item, layout, data: Option, wpos) {
        return new Promise(async (resolve, reject) => {

            let ball = pg.view.find(this.item_gun, 'ball');
            let startPos: cc.Vec2, targetPos: cc.Vec2 = wpos;
            if (wpos.x > 1334 / 2 + 200) {
                //向右飞出
                ball.active = true;
                startPos = cc.v2(-100, -280);
                targetPos = ball.parent.convertToNodeSpaceAR(wpos);
                ball.setPosition(startPos);
                cc.Tween.stopAllByTarget(ball);
                cc.tween(ball).to(0.5, { x: targetPos.x, y: targetPos.y }).call(() => {
                    ball.active = false;
                }).start();
                //弹弓动画。
                await this.playGun(GUN_STATE.SHUT_RIGHT);
            } else if (wpos.x < 1334 / 2 - 200) {
                //向左飞出
                ball.active = true;
                startPos = cc.v2(95, -340);
                targetPos = ball.parent.convertToNodeSpaceAR(wpos);
                ball.setPosition(startPos);
                cc.Tween.stopAllByTarget(ball);
                cc.tween(ball).to(0.5, { x: targetPos.x, y: targetPos.y }).call(() => {
                    ball.active = false;
                }).start();
                //弹弓动画。
                await this.playGun(GUN_STATE.SHUT_LEFT);
            } else {
                //向上飞出
                ball.active = true;
                startPos = cc.v2(-6, -352);
                targetPos = ball.parent.convertToNodeSpaceAR(wpos);
                cc.Tween.stopAllByTarget(ball);
                ball.setPosition(startPos);
                cc.tween(ball).to(0.5, { x: targetPos.x, y: targetPos.y }).call(() => {
                    ball.active = false;
                }).start();
                //弹弓动画。
                await this.playGun(GUN_STATE.SHUT_MIDDLE);
            }
            //爆炸效果
            this.updateFishState(item, FISH_STATE.BREAK);
            await pg.time.delay(0.5);
            //气球下落
            this.updateFishState(item, FISH_STATE.FALL);
            cc.tween(item).repeatForever(cc.tween().by(0.2, { x: 25 }).by(0.4, { x: -50 }).by(0.2, { x: 25 })).start();
            cc.tween(item).to(1.5, { y: -1000 }, { easing: cc.easing.quadIn }).call(async () => {
                //处理内容
                data.fish.isOut = FISH_OUT.OUT;
                await this.playCard(data);
                this.updateLayoutSpeak();
                resolve('');
            }).start();
            // data.audioUrl && pg.audio.playAudioByUrl(data.audioUrl)
        });
    }
    fishing(item, layout, wpos) {
        return new Promise(async (resolve, reject) => {
            let data = item.data;
            //item停止动画并
            cc.Tween.stopAllByTarget(item);
            await this.fishingRight(item, layout, data, wpos);
            return resolve(data.right);
        });
    }
    //开始点击     点击角色
    touchData: Option;
    async onTouchItem(e) {
        if (this.touching) return;
        let item: cc.Node = e.target;
        let p = e.touch.getLocation();
        let wpos = p;
        // let wpos = item.convertToWorldSpaceAR(p);
        let data = item.data;
        if (this.touchFishs.some(fish => fish.id == data.id)) return;
        if (data.fish.isOut != FISH_OUT.RUNNING) return;
        this.touching = true;
        this.touchData = data;
        data.fish.isOut = FISH_OUT.TOUCH;
        await this.fishing(item, this.layout_player, wpos);
    }
    //机器人随机钓鱼

    get fishLen() {
        if (!this.fishs) return 999;
        let arr = this.fishs.filter(item => {
            let data: Option = item.data;
            return data.fish.isOut == FISH_OUT.RUNNING;
        })
        this.fishs = arr;
        return this.fishs.length;
    }
    update(dt) {
        if (Game.getIns().state != GAME_STATE.RUNNING) return;
        if (this.touching) return;
        if (this.fishLen < 5) this.count++;
        let fish = this.getFishByCount(this.count);
        if (fish) this.fishs.push(fish);
    }
    updateTips(state?: TIPS_STATE) {
        if (!state) {
            this.layout_tip.active = false;
            return;
        }
        this.layout_tip.active = true;
        let img_light = pg.view.find(this.layout_tip, 'img_light');
        let img_co = pg.view.find(this.layout_tip, 'img_co');
        let img_gj = pg.view.find(this.layout_tip, 'img_gj');
        let img_ta = pg.view.find(this.layout_tip, 'img_ta');
        img_light.active = true;
        cc.Tween.stopAllByTarget(img_light)
        cc.tween(img_light).repeatForever(cc.tween().by(5, { angle: 360 })).start();
        img_co.active = false;
        img_gj.active = false;
        img_ta.active = false;
        let img = null;
        switch (state) {
            case TIPS_STATE.COM:
                img = img_co;
                this.playLocalAudio("co");
                break;
            case TIPS_STATE.GOOD:
                img = img_gj;
                this.playLocalAudio("gj");
                break;
            case TIPS_STATE.TRY:
                img = img_ta;
                this.playLocalAudio("ta");
                break;
        }
        img.scale = 0;
        img.active = true;
        cc.tween(img).to(0.5, { scale: 1 }).call(() => {
        }).start();
    }
    updateLayoutSpeak(hide?: boolean) {
        if (!hide) {
            this.layout_speak.active = true;
            let ske = pg.view.find(this.layout_speak, 'speak_ske');
            let btn_start = pg.view.find(this.layout_speak, 'btn_start');
            let btn_stop = pg.view.find(this.layout_speak, 'btn_stop');
            pg.view.touchOn(btn_start, this.onTouchRecord, this);
            pg.view.touchOn(btn_stop, this.onTouchRecordEnd, this);
            pg.view.playDBAnimation(ske, 'newAnimation', 0);
            ske.getComponent(dragonBones.ArmatureDisplay).timeScale = 0.00001;
            btn_start.active = true;
            btn_stop.active = false;
        } else {
            this.layout_speak.active = false;
        }
    }
    //按钮触发，使用的方法
    async onTouchRecord() {
        this.playLocalAudio("record")
        let ske = pg.view.find(this.layout_speak, 'speak_ske');
        let btn_start = pg.view.find(this.layout_speak, 'btn_start');
        let btn_stop = pg.view.find(this.layout_speak, 'btn_stop');
        btn_start.active = false;
        btn_stop.active = true;
        ske.getComponent(dragonBones.ArmatureDisplay).timeScale = 1;
        cc.audioEngine.stopAllEffects();

        let end = pg.view.find(this, "end");
        let bg_tryagain = pg.view.find(end, "bg_tryagain")
        pg.view.visible(end, false);
        pg.view.visible(bg_tryagain, false);

        courseware && courseware.startTest(this.touchData.txt); //开始录音
    }
    async onTouchRecordEnd() {
        this.playLocalAudio("record")
        let ske = pg.view.find(this.layout_speak, 'speak_ske');
        let btn_start = pg.view.find(this.layout_speak, 'btn_start');
        let btn_stop = pg.view.find(this.layout_speak, 'btn_stop');
        pg.view.playDBAnimation(ske, 'newAnimation', 1);
        ske.getComponent(dragonBones.ArmatureDisplay).timeScale = 10000;
        btn_stop.active = false;
        btn_start.active = false;
        let testData = {
            "dtLastResponse": "2021-09-17 13:36:26:109",
            "refText": "I haven't found anything out about him yet.",
            "recordId": "6144295213f0a2200000ed93",
            "eof": 1,
            "result": {
                "pronunciation": 25,
                "resource_version": "3.1.0",
                "fluency": 60,
                "rhythm": 90,
                "kernel_version": "5.2.4",
                "overall": 25,//75
                "integrity": 100,
                "duration": "6.779",
                "rear_tone": "fall",
                "speed": 96,
            },
            "tokenId": "6144295408558b08dd000001",
            "applicationId": "154838659000009e"
        }
        if (!courseware) return this.recrodEnd(testData)
        // await pg.time.delay(5);
        courseware && courseware.stopTest((data) => {
            data = JSON.parse(data);
            this.recrodEnd(data);
        }); //结束录音
    }
    private tryData: Array<Option>;
    private tryAgain: boolean = false;
    async recrodEnd(data) {
        Game.getIns().player.addVoice(data);
        let score = data.result.overall;
        if (score >= 70) {
            //提示成功
            this.updateTips(TIPS_STATE.GOOD);
            Game.getIns().player.addRight();
            this.touchFishs.push(this.touchData);
            this.tryAgain = false;
        } else {
            //提示失败
            if (this.tryData.some(td => td.id == this.touchData.id)) {
                this.updateTips(TIPS_STATE.COM);
                this.touchFishs.push(this.touchData);
                if (this.tryAgain) {
                    this.tryAgain = false;
                    this.playCard(null);
                    this.updateLayoutSpeak(true);
                    this.updateTips(null);
                    this.touching = false;
                    Game.getIns().state = GAME_STATE.OVER
                    return pg.event.emit("game_time_over");
                }
            } else {
                this.updateTips(TIPS_STATE.TRY);
                this.tryData.push(this.touchData);
                this.viewFishs = this.viewFishs.filter(v => v.id != this.touchData.id);
                this.tryAgain = this.tryAgain ? false : true;
            }
        }
        await pg.time.delay(3);
        this.updateTips(null);
        if (this.tryAgain) {
            this.playCard(this.touchData);
            this.updateLayoutSpeak()
        } else {
            this.playCard(null);
            this.updateLayoutSpeak(true)
            this.touching = false;
        }
    }


    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); });
        })
    }
}


