import { addBtnListener, asyncDelay, asyncTweenBy, asyncTweenTo, Between, exchangeNodePos, getSpriteFrimeByUrl, onHomeworkFinish, playAudioByUrlSync, RandomInt, showTrebleFirework } from "../script/util";
import { MyCocosSceneComponent } from "../script/MyCocosSceneComponent";

const { ccclass, property } = cc._decorator;

@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() {

    }
    createSpeed = []
    moveSpeed = []
    initSceneData() {
        super.initSceneData()
        this.createSpeed = [750, 1500, 1000, 800, 800, 640, 640, 512, 512];
        this.moveSpeed = [5, 5, 4, 4, 3.2, 3.2, 2.56, 2.56, 2.048, 2.048];
    }

    onLoadEnd() {
        // TODO 加载完成后的逻辑写在这里, 下面的代码仅供参考
        this.initData();
        this.initView();
        this.initListener();

        this.initData();


    }

    _cantouch = null;
    initData() {
        // 所有全局变量 默认都是null 
        this._cantouch = true;
    }

    recording: cc.Node = null;
    answerRightarr = []
    initView() {
        cc.find('Canvas').on('size-changed', this.onSizeChanged.bind(this));
        this.initBg();
        this.createStars();
        this.recording = this.node.getChildByName("recording")// cc.find('recording')
        this.recording.zIndex = 999
        this.recording.active = false
        // this.setcoordinate(this.recording)
        this.recording.getChildByName("good").active = false
        this.recording.getChildByName("Try").active = false
        this.recording.getChildByName("DB").active = true

        this.gameStart();
    }
    onSizeChanged() {
        cc.director.loadScene(cc.director.getScene().name);
    }
    initBg() {
        const bgNode = cc.find('Canvas/bg');
        bgNode.scale = this._mapScaleMax;

        const table = cc.find('Canvas/bg/Table');
        table.zIndex = 1;
        const gunBase = cc.find('Canvas/bg/GunBase');
        gunBase.zIndex = 1;
        const speaker = cc.find('Canvas/bg/BtnSpeaker');
        speaker.zIndex = 1;
    }

    createStars() {
        let length = 1;
        const starLayout = cc.find('Canvas/bg/StarLayout');
        starLayout.removeAllChildren();
        starLayout.zIndex = 2;
        const paddingY = starLayout.getComponent(cc.Layout).spacingY;

        if (this.data.questionList.length == 1) {
            starLayout.active = false;
        }

        for (let i = 0; i < this.data.questionList.length; i++) {
            const starBase = cc.instantiate(cc.find('StarBase'));
            starBase.name = `starBase_${i}`;
            starBase.scale = Between(0.5, (starLayout.height / length - paddingY) / starBase.height, 1);
            starBase.parent = starLayout;
        }

    }



    async showStar() {
        const starBase = cc.find(`Canvas/bg/StarLayout/starBase_${this._status.currentQuestionIdx}`);
        if (!starBase) {
            return;
        }
        const star = starBase.getChildByName('Star');
        star.active = true;
        const starBig = star.getChildByName('StarBig');
        starBig.scale = 1;
        star.active = true;
        star.scaleX = 0.7 / starBase.scale;
        star.scaleY = 1 / starBase.scale;
        star.angle = 90;
        const canvas = cc.find('Canvas');
        const startPos = star.parent.convertToNodeSpaceAR(canvas.convertToWorldSpaceAR(cc.v2(0, -canvas.height / 2)));
        const middlePos = star.parent.convertToNodeSpaceAR(canvas.convertToWorldSpaceAR(cc.v2(0, -canvas.height / 4)));
        star.x = startPos.x;
        star.y = startPos.y - starBig.height;

        this.playAudio('star');

        cc.tween(star)
            .to(0.3, { y: middlePos.y + 80 }, { easing: 'quadOut' })
            .to(0.1, { y: middlePos.y + 40, scaleX: 1.2 / starBase.scale, scaleY: 0.8 / starBase.scale }, { easing: 'quadOut' })
            .to(0.1, { y: middlePos.y, scaleX: 1 / starBase.scale, scaleY: 1 / starBase.scale }, { easing: 'quadOut' })
            .delay(0.1)
            .to(0.8, { angle: -720, scale: 1 })
            .start();

        cc.tween(star)
            .delay(0.6)
            .to(0.8, { x: 0 }, { easing: 'quadIn' })
            .start();
        cc.tween(star)
            .delay(0.6)
            .to(0.8, { y: 0 }, { easing: 'quadOut' })
            .start();

        await asyncDelay(0.6);
        await asyncTweenTo(starBig, 0.8, { scale: 0 }, { easing: 'quadOut' });
        await this.playAudioSync('question');
    }

    isEndGame() {
        return this._status.currentQuestionIdx >= this.data.questionList.length;
    }

    onGameEnd() {
        showTrebleFirework(cc.find('Canvas/bg'), cc.find('RabbonBase').children);
        this.playAudio('end');
        onHomeworkFinish();
        this.hideGuns();
        
        // TODO 上报成绩，现在这里没采集成绩，所以后续再实现
        window["courseware"].sendAnswer({"gameEnd": true});
        window["courseware"].nextPage();

    }
    _status = null
    async gameStart() {
        this._status = {
            currentQuestionIdx: 0,
            currentRightNumber: 0
        };
        this.createStars();
        await this.showGuns();

        await this.playQuestionAudio();
        this.startShowBalls();
    }

    showGuns() {
        return new Promise((resolve, reject) => {
            try {
                const bg = cc.find('Canvas/bg');
                const gunBase = cc.find('Canvas/bg/GunBase');
                asyncTweenTo(gunBase, 0.5, { y: -bg.height / 2 });
                this.playAudio('move', () => {
                    resolve(0);
                });
            } catch (e) {
                reject();
            }
        });
    }

    hideGuns() {
        const bg = cc.find('Canvas/bg');
        const gunBase = cc.find('Canvas/bg/GunBase');
        this.playAudio('move');
        asyncTweenTo(gunBase, 0.5, { y: -bg.height / 2 - gunBase.height });
    }

    showBallsinterval = null
    ballList = null;
    startShowBalls() {
        this.answerRightarr = []
        const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
        const answerList = currentQuestion.answerList;
        const time = this.createSpeed[currentQuestion.speedLevel];

        this.ballList = [];

        const answer = answerList[RandomInt(answerList.length)];
        const ball = this.createBall(answer);
        this.ballList.push(ball);
        this.showBallsinterval = setInterval(() => {
            const answer = answerList[RandomInt(answerList.length)];
            const ball = this.createBall(answer);
            this.ballList.push(ball);
        }, time);
        console.log("startShowBalls", answerList);
        for (let k = 0; k < answerList.length; k++) {
            if (answerList[k].rightAnswer && answerList[k].answerTxt != "") {
                this.answerRightarr.push(answerList[k].answerTxt)
            }
        }
    }

    stopShowBalls() {
        if (this.showBallsinterval) {
            clearInterval(this.showBallsinterval);
        }
        if (this.ballList) {
            this.ballList.forEach(ball => {
                ball.stopAllActions();
                cc.tween(ball)
                    .to(0.5, { opacity: 0 })
                    .removeSelf()
                    .start();
            });
            this.ballList = [];
        }
    }


 
    recordingEvent(e, state) {
        
    }

    conclusion(grade) {
        if (grade >= 60) {
            this.recording.getChildByName("good").active = true
            this.playAudio("good")
        } else {
            this.recording.getChildByName("Try").active = true
            this.playAudio("again")
        }
        this.recording.getChildByName("DB").active = false
        this.scheduleOnce(() => {
            if(!this.node.isValid)return
            this.recording.active = false
            this.recording.getChildByName("good").active = false
            this.recording.getChildByName("Try").active = false
            this.recording.getChildByName("DB").active = true
            this.over()
        }, 2)
    }
    async over() {
        await this.showStar();
        this._status.currentRightNumber = 0;
        this._status.currentQuestionIdx++;
        if (this.isEndGame()) {
            this.onGameEnd();
        } else {
            await asyncDelay(1.5);
            await this.playQuestionAudio();
            this.startShowBalls();
        }
    }
    operation(e, state) {
        this.playAudio("btn");
        this.recording.getChildByName("good").active = false
        this.recording.getChildByName("Try").active = false
        this.recording.getChildByName("DB").active = true
        if (state == "0") {//再来一次
        } else {//跳过 继续游戏
            this.recording.active = false
            this.over()
        }
    }

    lastBallPosXBase = null;
    createBall(answer) {
        let ball = null;
        if (answer.answerType == 'img') {
            ball = this.createImgBall(answer);
        } else {
            ball = this.createTextBall(answer);
        }

        const bg = cc.find('Canvas/bg');
        let ballPosXBaseList = [-bg.width / 4, 0, bg.width / 4];
        if (this.lastBallPosXBase !== undefined) {
            ballPosXBaseList = ballPosXBaseList.filter(posX => posX != this.lastBallPosXBase);
        }

        const ballPosXBase = ballPosXBaseList[RandomInt(ballPosXBaseList.length)];
        ball.x = ballPosXBase + RandomInt(-50, 50);
        ball.y = -bg.height / 2;
        ball.parent = bg;

        this.lastBallPosXBase = ballPosXBase;

        if (answer.rightAnswer) {
            ball.audio = answer.answerAudio;
        }

        cc.tween(ball.getChildByName('bg'))
            .to(0.2, { scaleX: 0.98, scaleY: 1.05 })
            .to(0.2, { scaleX: 1.02, scaleY: 0.94 })
            .union()
            .repeatForever()
            .start();

        this.playAudio('appare', null, 0.1);

        ball.on('touchstart', async (event) => {
            if (ball.canNotTouch) {
                return;
            }
            if (answer.rightAnswer) {
                ball.canNotTouch = true;
            }
            const location = event.getLocation();
            await this.shootTarget(ball, location, true);
            if (!answer.rightAnswer) {
                this.targetLaugh(ball);
                return;
            }
            this.targetDistroy(ball);
            this._status.currentRightNumber++;
            const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
            this.updateRightNumber();
            if (this._status.currentRightNumber >= currentQuestion.rigthNumber) {
                this.log("打完了=============")
                this.stopShowBalls();
                await asyncDelay(2);
                this.recording.active = true;
                await this.autoRecording();
            }
        });

        const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
        const time = this.moveSpeed[currentQuestion.speedLevel];
        const targetY1 = bg.height / 2 - ball.height / 2 - 50;
        const targetY2 = bg.height;
        const time1 = time * (ball.y - targetY1) / (ball.y - targetY2);
        const time2 = time - time1;
        cc.tween(ball)
            .to(time1, { y: bg.height / 2 - ball.height / 2 - 50 }, { easing: 'quadOut' })
            .delay(0.5)
            .to(time2, { y: bg.height }, { easing: 'quadIn' })
            .removeSelf()
            .start();

        ball.moveSpeed = bg.height / time;
        return ball;
    }

    async autoRecording() {
        const courseware = (<any>window).courseware;
        if (!courseware) {
            this.conclusion(6);
            return;
        }
        courseware.startTest(this.answerRightarr[0]);
        await asyncDelay(3);
        courseware.stopTest((res) => { // 这里面是一个评测对象，里面有各种维度的评分
            let str = JSON.parse(res)
            this.conclusion(str.result.overall)
        });
    }

    onBallClicked(answer) {

    }

    createImgBall(answer) {
        const ball = cc.instantiate(cc.find('BallImg'));
        const img = cc.find('Mask/AnsterImg', ball);
        const mask = cc.find('Mask', ball);
        getSpriteFrimeByUrl(answer.answerImg, (spriteFrame) => {
            img.getComponent(cc.Sprite).spriteFrame = spriteFrame;
            img.scale = Math.min(1, mask.width / img.width, mask.height / img.height);
        });
        return ball;
    }

    createTextBall(answer) {
        const ball = cc.instantiate(cc.find('BallTxt'));
        const mask = cc.find('Mask', ball);
        const text = cc.find('Mask/AnswerText', ball);
        text.getComponent(cc.RichText).string = `<color=#37397b>${answer.answerTxt}</color>`;

        cc.tween(text)
            .delay(0)
            .call(() => {
                text.scale = Math.min(mask.width / text.width, 1);
            })
            .start();

        return ball;
    }

    updateRightNumber() {
        this._status.currentRightNumber;
        const totalRightNumber = this.data.questionList[this._status.currentQuestionIdx].rigthNumber;
        const starBase = cc.find(`Canvas/bg/StarLayout/starBase_${this._status.currentQuestionIdx}`);
        const mask = starBase.getChildByName('Mask');
        const bg = starBase.getChildByName('bg');

        cc.tween(mask)
            .to(0.3, { height: bg.height * (this._status.currentRightNumber / totalRightNumber) })
            .start();
    }

    async playQuestionAudio() {
        if (!this._status) {
            return;
        }
        const currentQuestion = this.data.questionList[this._status.currentQuestionIdx];
        if (!currentQuestion) {
            return;
        }
        this.speakerBlink();
        await playAudioByUrlSync(currentQuestion.questionAudio);
        this.speakerStopBlink();
    }
    speakerList = null
    speakerBlink() {
        const btnSpeaker = cc.find(`Canvas/bg/BtnSpeaker`);
        btnSpeaker.getComponent(cc.Animation).play();
    }

    speakerStopBlink() {
        const btnSpeaker = cc.find(`Canvas/bg/BtnSpeaker`);
        const btnSpeaker3 = cc.find(`Canvas/bg/BtnSpeaker/speaker_3`);
        btnSpeaker.getComponent(cc.Animation).stop();
        btnSpeaker.getComponent(cc.Sprite).spriteFrame = btnSpeaker3.getComponent(cc.Sprite).spriteFrame;
    }

    async shootTarget(node, location, shootBullet) {
        const GunPos = cc.find('Canvas/bg/GunBase/GunPos');
        const Gun = cc.find('Canvas/bg/GunBase/Gun');
        const Water = cc.find('Canvas/bg/GunBase/Gun/Water');
        const Muzzle = cc.find('Canvas/bg/GunBase/Gun/Muzzle');
        const bg = cc.find('Canvas/bg')
        let offsetY = 0;
        if (node.moveSpeed) {
            offsetY = node.moveSpeed * 0.4;
        }
        const shootSide = GunPos.convertToNodeSpaceAR(cc.v2(location.x, location.y + offsetY));

        const bullet = cc.instantiate(cc.find('Bullet'));
        bullet.parent = bg;
        bullet.scaleY = 0;
        if (!shootBullet) {
            bullet.opacity = 0;
        }

        const angle = cc.v2(0, 1).signAngle(shootSide) * 180 / Math.PI;
        bullet.angle = angle;

        asyncTweenTo(Water, 0.1, { angle: -angle });
        await asyncTweenTo(Gun, 0.1, { angle: angle, scaleY: 0.95 });
        let startPos = exchangeNodePos(bg, Muzzle);
        bullet.x = startPos.x;
        bullet.y = startPos.y;

        cc.tween(Gun)
            .to(0.1, { scaleX: 0.95, scaleY: 1.05 })
            .to(0.1, { scaleX: 1, scaleY: 1 })
            .start();

        this.playAudio('light');

        let targetPos = bg.convertToNodeSpaceAR(cc.v2(location.x, location.y + offsetY));
        let flySide = cc.v2(targetPos.x - startPos.x, targetPos.y - startPos.y);
        await asyncTweenTo(bullet, 0.1, {
            scaleY: flySide.mag() / bullet.height,
            scaleX: Between(0.5, 1, bullet.height / flySide.mag())
        });

        bullet.setAnchorPoint(0.5, 1);
        bullet.x = targetPos.x;
        bullet.y = targetPos.y;

        asyncTweenTo(bullet, 0.2, { opacity: 0, scaleY: 0 });
    }

    async targetDistroy(node) {
        node.stopAllActions();
        const bg = node.getChildByName('bg');
        bg.active = false;
        const DistroyAnime = node.getChildByName('DistroyAnime');
        DistroyAnime.active = true;
        const Mask = node.getChildByName('Mask');
        cc.tween(Mask)
            .to(0.5, { opacity: 0 })
            .start();

        await this.playAudioSync('right');
        await playAudioByUrlSync(node.audio);
        node.removeFromParent();
    }

    async targetLaugh(node) {
        this.playAudio('wrong');
        const x = node.x;
        let offsetX = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
        let offsetY = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
        await asyncTweenBy(node, 0.05, { x: offsetX, y: offsetY });
        offsetX = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
        offsetY = RandomInt(20, 50) * 2 * (RandomInt(2) - 0.5);
        await asyncTweenBy(node, 0.05, { x: offsetX, y: offsetY });
        await asyncTweenTo(node, 0.05, { x: x });
    }

    playAudio(audioName, cb = null, value = 0.8) {
        const audioNode = cc.find(`AudioBase/${audioName}`);
        const audioClip = audioNode.getComponent(cc.AudioSource).clip;
        const id = cc.audioEngine.play(audioClip, false, value);
        cc.audioEngine.setFinishCallback(id, () => {
            if (cb) {
                cb();
            }
        });
    }
    async playAudioSync(audioName, value = 0.8) {
        return new Promise((resolve, reject) => {
            try {
                this.playAudio(audioName, () => {
                    resolve(0);
                }, value);
            } catch (e) {
                reject();
            }
        });
    }

    initListener() {
        const BtnStart = cc.find('Canvas/bg/BtnStart');
        addBtnListener(BtnStart, async () => {
            await asyncTweenTo(BtnStart, 0.1, { opacity: 0 });
            BtnStart.active = false;
            this.gameStart();
        }, this.playAudio.bind(this, 'btn'));
        const BtnRestart = cc.find('Canvas/bg/BtnRestart');
        addBtnListener(BtnRestart, async () => {
            await asyncTweenTo(BtnRestart, 0.1, { opacity: 0 });
            BtnRestart.active = false;
            this.gameStart();
        }, this.playAudio.bind(this, 'btn'));
        const BtnSpeaker = cc.find('Canvas/bg/BtnSpeaker');
        addBtnListener(BtnSpeaker, async () => {
            await this.playQuestionAudio();
        });

        const bg = cc.find('Canvas/bg');
        bg.on('touchstart', (event) => {
            this.shootTarget(bg, event.getLocation(), false);
        });
    }

}
