// Learn cc.Class:
//  - https://docs.cocos.com/creator/manual/en/scripting/class.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
const defaultData = require('../script/choose_cake_defaultData');
import {
    exchangeNodePos,
    asyncTweenTo,
    asyncTweenBy,
    asyncPlayDragonBoneAnimation,
    randomSortByArr,
    asyncPlayEffectByUrl,
    RandomInt
} from '../script/choose_cake_utils';

cc.Class({
    extends: cc.Component,
    properties: {
        cakePrefab: {
            type: cc.Prefab,
            default: null,
        },
        starPrefab: {
            type: cc.Prefab,
            default: null,
        },
    },

    ctor() {
        this._imageResList = [];
        this._audioResList = [];
        this._status = {
            selectedRightWordList: [],
            canCharacterWalk: false
        }
    },

    start() {
        this.data = defaultData;
        this.getData((data) => {
            if (data) {
                this.data = data;
            }
            this.preloadItem();
        });
        this.initListeners();
    },

    getData(func) {
        if (window && window.courseware) {
            window.courseware.getData(func, 'choose_cake');
        } else {
            func(defaultData);
        }
    },

    _imageResList: null,
    _audioResList: null,
    preloadItem() {
        this.addPreloadImage();
        this.addPreloadAudio();
        this.preload();
    },

    addPreloadImage() { },

    addPreloadAudio() {
        this._audioResList.push({ url: this.data.audio });
        this._audioResList.push(...this.data.rightWordList.map(data => ({ url: data.audio })));
        this._audioResList.push(...this.data.wrongWordList.map(data => ({ url: data.audio })));
    },

    preload() {
        const preloadArr = this._imageResList.concat(this._audioResList);
        cc.assetManager.loadAny(preloadArr, null, null, (err, data) => {
            this.hideAirClassLoading();
        });
        if (preloadArr.length == 0) {
            this.hideAirClassLoading();
        }
    },

    hideAirClassLoading() {
        if (window && window["air"]) {
            window["air"].hideAirClassLoading();
        }
        console.log('hideAirClassLoading');
    },

    initListeners() {
        const btnStart = cc.find('Canvas/BtnStart');
        btnStart.on('click', () => {
            cc.tween(btnStart)
                .to(0.3, { scale: 3, opacity: 0 })
                .call(() => {
                    btnStart.active = false;
                    this.gameStart();
                })
                .start();
        });
        const btnRestart = cc.find('Canvas/BtnRestart');
        btnRestart.on('click', () => {
            cc.tween(btnRestart)
                .to(0.3, { scale: 3, opacity: 0 })
                .call(() => {
                    btnRestart.active = false;
                    cc.audioEngine.stopAll();
                    cc.director.loadScene('choose_cake');
                })
                .start();
        });

        const nodeDesk = cc.find('Canvas/NodeDesk');
        nodeDesk.on('touchstart', (event) => {
            this.onTouchDeskStart({
                x: event.getLocationX() - nodeDesk.width * nodeDesk.anchorX,
                y: event.getLocationY() - nodeDesk.height * nodeDesk.anchorY
            })
        });
    },

    onTouchDeskStart(pos) {
        if (this._status.canCharacterWalk) {
            this.characterWalk({ x: pos.x, y: pos.y + 50 });
        }
    },

    characterWalk(pos, speed = 1, changeActive = false) {
        return new Promise((resolve, reject) => {
            const nodeCharacter = cc.find('Canvas/NodeCharacter');
            nodeCharacter.stopAllActions();

            var walkVec = cc.v2(nodeCharacter.x - pos.x, nodeCharacter.y - pos.y);
            const time = walkVec.mag() / 300;

            const nodeCharacterUp = cc.find('Canvas/NodeCharacter/NodeCharacterUp');
            const nodeCharacterDown = cc.find('Canvas/NodeCharacter/NodeCharacterDown');
            const nodeCharacterLeft = cc.find('Canvas/NodeCharacter/NodeCharacterLeft');
            const nodeCharacterRight = cc.find('Canvas/NodeCharacter/NodeCharacterRight');
            const nodeCharacterFront = cc.find('Canvas/NodeCharacter/NodeCharacterFront');

            nodeCharacterUp.active = false;
            nodeCharacterDown.active = false;
            nodeCharacterLeft.active = false;
            nodeCharacterRight.active = false;
            nodeCharacterFront.active = false;

            if (walkVec.x >= walkVec.y && walkVec.x >= -walkVec.y) {
                nodeCharacterLeft.active = true;
                asyncPlayDragonBoneAnimation(nodeCharacterLeft, 'left', -1);
            }
            if (walkVec.x < walkVec.y && walkVec.x < -walkVec.y) {
                nodeCharacterRight.active = true;
                asyncPlayDragonBoneAnimation(nodeCharacterRight, 'right', -1);
            }
            if (walkVec.x >= walkVec.y && walkVec.x < -walkVec.y) {
                nodeCharacterUp.active = true;
                asyncPlayDragonBoneAnimation(nodeCharacterUp, 'back', -1);
            }
            if (walkVec.x < walkVec.y && walkVec.x >= -walkVec.y) {
                nodeCharacterDown.active = true;
                asyncPlayDragonBoneAnimation(nodeCharacterDown, 'heads', -1);
            }

            cc.tween(nodeCharacter)
                .to(time * speed, { x: pos.x, y: pos.y })
                .call(() => {
                    if (!changeActive) {
                        nodeCharacterUp.active = false;
                        nodeCharacterLeft.active = false;
                        nodeCharacterRight.active = false;
                        nodeCharacterDown.active = false

                        nodeCharacterFront.active = true;
                    }

                    resolve();
                })
                .start();
        });
    },

    gameStart() {
        this.playEffect('bgm', true, 0.5);
        this.showCakes();
        this.showCharacter();
    },

    async showCharacter() {
        await this.openDeskDoor();
        await this.riseCharacter();
        await this.closeDeskDoor();
        this._status.canCharacterWalk = true;
        asyncPlayEffectByUrl(this.data.audio);
    },

    async showCakes() {
        const { rightWordList, wrongWordList } = this.data;
        let wordList = randomSortByArr([...rightWordList.map(data => data.word), ...wrongWordList.map(data => data.word)]);

        wordList.forEach((data, idx) => {
            let cakeNode = cc.instantiate(this.cakePrefab);
            cakeNode.getComponent('choose_cake_Cake').setWord(data);
            cakeNode.zIndex = 12;
            cakeNode.opacity = 0;
            cakeNode.y = 500;
            cakeNode.parent = this.node;
            cakeNode.name = `CakeNode_${idx}`;

            const posNode = cc.find(`Canvas/PosNodeBase/CakePosNode_${idx}`);
            const targetPos = exchangeNodePos(cakeNode.parent, posNode);

            cakeNode.on('click', () => {
                this.onClickCake(idx);
            });

            cc.tween(cakeNode)
                .to(0.1 * idx, { opacity: 255 })
                .to(0.5, { x: targetPos.x, y: targetPos.y }, { easing: 'cubicIn' })
                .call(() => {
                    this.playEffect('落地');
                })
                .start();
        });

    },

    async onClickCake(idx) {
        if (!this._status.canCharacterWalk) {
            return;
        }
        const cakeNode = cc.find(`Canvas/CakeNode_${idx}`);

        this._status.canCharacterWalk = false;

        await this.characterWalk(cakeNode.getPosition());

        await asyncTweenBy(cakeNode, 0.7, { y: 100 });

        this.playCakeEffect(cakeNode);
        this.characterGetCake(cakeNode);
        await this.characterWalk({ x: 0, y: 50 });

        this.characterReleaseCake(cakeNode);
        if (this.checkCake(cakeNode)) {
            await this.npcPlayAnimRight(cakeNode);
        } else {
            await this.npcPlayAnimWrong(cakeNode, idx);
        }

        if (this.checkOver()) {
            this.showOver();
            return;
        }

        asyncPlayEffectByUrl(this.data.audio);
        this._status.canCharacterWalk = true;
    },

    playCakeEffect(cakeNode) {
        const word = cakeNode.getComponent('choose_cake_Cake').word;

        const wordData = [
            ...this.data.rightWordList,
            ...this.data.wrongWordList
        ].find(data => data.word == word);

        asyncPlayEffectByUrl(wordData.audio);
    },

    characterGetCake(cakeNode) {
        cakeNode.parent = cc.find('Canvas/NodeCharacter');
        cakeNode.x = 0;
        cakeNode.y = 100;
    },

    characterReleaseCake(cakeNode) {
        const pos = exchangeNodePos(cakeNode.parent, this.node);
        cakeNode.parent = this.node;
        cakeNode.x = pos.x;
        cakeNode.y = pos.y + 200;
    },

    checkCake(cakeNode) {
        const word = cakeNode.getComponent('choose_cake_Cake').word;

        if (this.data.rightWordList.findIndex(data => data.word == word) == -1) {
            return false;
        }

        this._status.selectedRightWordList.push(word);

        return true;
    },

    checkOver() {
        return this._status.selectedRightWordList.length == this.data.rightWordList.length;
    },

    async showOver() {
        this.hideNpc();
        await this.hideCakes();

        await this.showStars();

        await this.moveCamera();

        await this.openDoor();
        await this.characterMoveOut();

        await this.showRestartBtn();
    },

    hideNpc() {
        const nodeNpc = cc.find('Canvas/NodeNpc');
        cc.tween(nodeNpc)
            .by(1, { y: 350 })
            .repeatForever()
            .start();
    },

    hideCakes() {
        for (let i = 0; i < 5; i++) {
            const cakeNode = cc.find(`Canvas/CakeNode_${i}`)

            if (!cakeNode) {
                continue;
            }
            // cakeNode.zIndex = 100;
            cc.tween(cakeNode)
                .by(1, { y: 350 })
                .repeatForever()
                .start();
        }
    },

    showStars() {
        this.playEffect('星星');
        for (let index = 0; index < 70; index++) {
            let starNode = cc.instantiate(this.starPrefab);
            starNode.x = RandomInt(-640, 640);
            starNode.y = RandomInt(360, 1800);
            starNode.parent = this.node;
            starNode.zIndex = 20;

            cc.tween(starNode)
                .by(1, { y: -300, angle: 360 })
                .repeatForever()
                .start();

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

    moveCamera() {
        const camera = cc.find('Canvas/Main Camera');
        cc.tween(camera)
            .delay(2)
            .by(1, { y: 1036 - 720 })
            .start();
    },

    openDoor() {
        const delayTime = 2;
        const nodeWheel1 = cc.find('Canvas/NodeDoorMask/NodeWheel1');
        const nodeWheel2 = cc.find('Canvas/NodeDoorMask/NodeWheel2');
        const nodeWheel3 = cc.find('Canvas/NodeDoorMask/NodeWheel3');

        cc.tween(nodeWheel1)
            .delay(delayTime)
            .call(() => {
                this.playEffect('门');
            })
            .by(1, { x: 200 })
            .start();
        cc.tween(nodeWheel2)
            .delay(delayTime)
            .by(1, { x: -200 })
            .start();
        cc.tween(nodeWheel3)
            .delay(delayTime)
            .by(1, { y: -200 })
            .start();
    },

    async characterMoveOut() {
        await this.characterWalk({ x: 0, y: 380 }, 4, true);

        const nodeCharacterUp = cc.find('Canvas/NodeCharacter/NodeCharacterUp');
        const nodeCharacterFront = cc.find('Canvas/NodeCharacter/NodeCharacterFront');

        nodeCharacterUp.active = true;
        nodeCharacterFront.active = false;

        const nodeDoorFront = cc.find('Canvas/NodeDoorFront');
        nodeDoorFront.zIndex = 100;

        cc.tween(nodeDoorFront)
            .to(1, { opacity: 255 })
            .start();
    },

    showRestartBtn() {
        const btnRestart = cc.find('Canvas/BtnRestart');
        btnRestart.active = true;
    },

    async npcPlayAnimRight(cakeNode) {
        this.playEffect('吃');
        const nodeNpcNormal = cc.find('Canvas/NodeNpc/NodeNpcNormal');
        const nodeNpcRight = cc.find('Canvas/NodeNpc/NodeNpcRight');

        nodeNpcNormal.active = false;
        nodeNpcRight.active = true;

        cakeNode.zIndex = 0;

        cc.tween(cakeNode)
            .to(0.1, { scale: 0.7 })
            .to(1, { scale: 0 })
            .call(() => {
                this.playEffect('正确');
            })
            .start();

        await asyncPlayDragonBoneAnimation(nodeNpcRight, 'npcright', 1);
        nodeNpcNormal.active = true;
        nodeNpcRight.active = false;

        // cakeNode
    },

    async npcPlayAnimWrong(cakeNode, idx) {
        this.playEffect('吃');

        const nodeNpcNormal = cc.find('Canvas/NodeNpc/NodeNpcNormal');
        const nodeNpcWrong = cc.find('Canvas/NodeNpc/NodeNpcWrong');

        nodeNpcNormal.active = false;
        nodeNpcWrong.active = true;

        cakeNode.zIndex = 0;

        const posNode = cc.find(`Canvas/PosNodeBase/CakePosNode_${idx}`);
        cc.tween(cakeNode)
            .to(0.1, { scale: 0.7 })
            .delay(1.5)
            .call(() => {
                this.playEffect('错误');
            })
            .to(0.5, { x: posNode.x, y: posNode.y, scale: 1 }, { easing: 'cubicOut' })
            .call(() => {
                this.playEffect('落地');
            })
            .start();

        await asyncPlayDragonBoneAnimation(nodeNpcWrong, 'npcwrong', 1);
        cakeNode.zIndex = 12;
        nodeNpcNormal.active = true;
        nodeNpcWrong.active = false;
    },

    openDeskDoor() {
        return new Promise((resolve, reject) => {
            const nodeDoorLeft = cc.find('Canvas/NodeDoorLeft');
            cc.tween(nodeDoorLeft)
                .to(0.5, { x: -150 })
                .start();

            const nodeDoorRight = cc.find('Canvas/NodeDoorRight');
            cc.tween(nodeDoorRight)
                .to(0.5, { x: 150 })
                .call(resolve)
                .start();
        });
    },

    closeDeskDoor() {
        return new Promise((resolve, reject) => {
            const nodeDoorLeft = cc.find('Canvas/NodeDoorLeft');
            cc.tween(nodeDoorLeft)
                .to(0.5, { x: 0 })
                .start();

            const nodeDoorRight = cc.find('Canvas/NodeDoorRight');
            cc.tween(nodeDoorRight)
                .to(0.5, { x: 0 })
                .call(resolve)
                .start();
        });
    },

    riseCharacter() {
        return new Promise((resolve, reject) => {
            const nodeDeskMask = cc.find('Canvas/NodeDeskMask');
            nodeDeskMask.zIndex = 11;

            const nodeCharacter = cc.find('Canvas/NodeCharacter');
            nodeCharacter.zIndex = 10;
            cc.tween(nodeCharacter)
                .to(1, { y: 75 })
                .call(() => {
                    nodeDeskMask.zIndex = 0;
                    resolve();
                })
                .start();
        });
    },

    playEffect(name, loop, volume) {
        let musicComponent = cc.find('Canvas/MusicNode').getComponent('choose_cake_MusicNode');
        musicComponent.playEffect(name, loop, volume);
    }
    // update (dt) {},
});
