// 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/defaultData');
import {
    asyncTweenTo,
    asyncTweenBy,
    asyncDelay,
    asyncPlayDragonBoneAnimation,
    asyncPlayEffectByUrl,
    RandomInt,
    Between,
    http,
    dateFormat,
    formatSeconds,
    jelly
} from '../script/utils';

cc.Class({
    extends: cc.Component,

    properties: {

        letter: 'b',

        bgNode: {
            type: cc.Prefab,
            default: null,
        },

        monkeyUpperNode: {
            type: cc.Prefab,
            default: null,
        },

        letterPageUINode: {
            type: cc.Prefab,
            default: null,
        },

        cloudPrefab: {
            type: cc.Prefab,
            default: null,
        },

        starAnimePrefab: {
            type: cc.Prefab,
            default: null,
        },
        starPreFab: {
            type: cc.Prefab,
            default: null,
        },
        sharkPreFab: {
            type: cc.Prefab,
            default: null,
        },
        arrowPrefab: {
            type: cc.Prefab,
            default: null,
        },
    },

    // LIFE-CYCLE CALLBACKS:

    // onLoad () {},

    courseid: null,
    ctor() {
        this._imageResList = [];
        this._audioResList = [];
        this.courseid = 111452;
    },

    start() {
        cc.debug.setDisplayStats(false);
        this.showLoadingPage();
        this.data = defaultData;
        this.getData((data) => {
            if (data) {
                this.data = data;
            }
            this.preloadItem();
        });
    },

    getData(func) {

        http('GET', 'https://staging-teach.ireadabc.com/api/courseware/v1/getdata?courseid=' + this.courseid, {}).then((resStr) => {
            const res = JSON.parse(resStr)
            const data = JSON.parse(res.data);
            func(data);
            console.log('res: ', res);
        });

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

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

    addPreloadImage() { },

    addPreloadAudio() { },

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

        const letterList = 'abcdefghijklmnopqrstuvwxyz'.split('');
        for (let i = 0; i < letterList.length; i++) {
            const letter = letterList[i];
            this[`letter${letter.toUpperCase()}Prefab`] = await this.loadAssetSync({ path: `prefabs/letter_big/prefab_big_${letter.toLowerCase()}` }, cc.Prefab);
            this[`letter${letter.toLowerCase()}Prefab`] = await this.loadAssetSync({ path: `prefabs/letter_small/prefab_small_${letter.toLowerCase()}` }, cc.Prefab);

            const letterPicSpriteFrame = await this.loadAssetSync({ path: `letterPic/bg_${letter.toLowerCase()}` }, cc.SpriteFrame);
            var letterPicNode = new cc.Node("New Sprite");
            letterPicNode.parent = cc.find('Canvas/LetterPicturePage/LetterPicture');
            letterPicNode.name = `bg_${letter.toLowerCase()}`;
            letterPicNode.active = false;

            var sprite = letterPicNode.addComponent(cc.Sprite);
            sprite.spriteFrame = letterPicSpriteFrame;
        }
    },

    async loadAssetSync(src, type) {
        return new Promise((resolve, reject) => {
            cc.resources.load(src, type, (err, prefab) => {
                resolve(prefab);
            });
        });
    },

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

    initListeners() {
        const btnSwitch = cc.find('Canvas/LetterPicturePage/BtnSwitch');
        const changeToBig = cc.find('Canvas/LetterPicturePage/BtnSwitch/ChangeToBig');
        const changeToSmall = cc.find('Canvas/LetterPicturePage/BtnSwitch/ChangeToSmall');
        const smallLetterBase = cc.find('Canvas/LetterPicturePage/SmallLetterBase');
        const bigLetterBase = cc.find('Canvas/LetterPicturePage/BigLetterBase');
        const pictureWordSmallBg = cc.find('Canvas/LetterPicturePage/PictureWordSmallBg');
        const pictureWordBigBg = cc.find('Canvas/LetterPicturePage/PictureWordBigBg');

        btnSwitch.on('click', () => {
            this.playEffect('按钮');

            changeToBig.active = !changeToBig.active;
            bigLetterBase.active = !bigLetterBase.active;
            pictureWordBigBg.active = !pictureWordBigBg.active;

            changeToSmall.active = !changeToSmall.active;
            smallLetterBase.active = !smallLetterBase.active;
            pictureWordSmallBg.active = !pictureWordSmallBg.active;
        });

        smallLetterBase.on('click', () => {
            this.playEffect(`letter${this.letter.toLowerCase()}`);
            cc.tween(smallLetterBase)
                .to(0.1, { angle: 5 })
                .to(0.1, { angle: -5 })
                .to(0.1, { angle: 0 })
                .start();
        });
        bigLetterBase.on('click', () => {
            this.playEffect(`letter${this.letter.toUpperCase()}`);
            cc.tween(bigLetterBase)
                .to(0.1, { angle: 5 })
                .to(0.1, { angle: -5 })
                .to(0.1, { angle: 0 })
                .start();
        });
        pictureWordSmallBg.on('click', () => {
            jelly(pictureWordSmallBg);
            this.playEffect(`word${this.letter.toUpperCase()}`);
        });
        pictureWordBigBg.on('click', () => {
            jelly(pictureWordBigBg);
            this.playEffect(`word${this.letter.toUpperCase()}`);
        });

        let btnClicked = false;
        const btnBefore = cc.find('Canvas/LetterPicturePage/BtnBefore');
        const btnNext = cc.find('Canvas/LetterPicturePage/BtnNext');
        btnBefore.on('click', async () => {
            if (btnClicked) {
                return;
            }
            btnClicked = true;
            this.playEffect('按钮');
            await jelly(btnBefore);

            this._status.currentLetterIdx--;
            this._status.currentLetterIdx = Math.max(this._status.currentLetterIdx, 0);

            this.updateLetter();
            btnClicked = false;
        });
        btnNext.on('click', async () => {
            if (btnClicked) {
                return;
            }
            btnClicked = true;
            this.playEffect('按钮');
            await jelly(btnNext);

            this._status.currentLetterIdx++;
            this._status.currentLetterIdx = Math.min(this._status.currentLetterIdx, this.data.letterList.length - 1);

            this.updateLetter();
            btnClicked = false;
        });
    },

    onLoadFinish() {

        this.initScrollView();
        this.initReplayBtn();

        this.initListeners();

        this._status = {
            currentLetterIdx: 0,
            currentStrokeIdx: 0,
            currentStrokeStageIdx: 0
        }
        this.updateLetter();

        this.hideLoadingPage();
    },



    updateLetter() {
        this.letter = this.data.letterList[this._status.currentLetterIdx];
        this.letter = this.letter.toUpperCase();
        this.createLetterPage(this.letter);
        this.updatePicturePage();
    },

    updatePicturePage() {
        const bigLetter = cc.find('Canvas/LetterPicturePage/BigLetterBase/BigLetter');
        bigLetter.getComponent(cc.Label).string = this.letter.toUpperCase();
        const smallLetter = cc.find('Canvas/LetterPicturePage/SmallLetterBase/SmallLetter');
        smallLetter.getComponent(cc.Label).string = this.letter.toLowerCase();

        const bgListToLetter = ['QV', 'CHKUX', 'BGIW', 'AEJNOY', 'DFLMPRSTZ'];
        const showBgIdx = bgListToLetter.findIndex(str => str.indexOf(this.letter.toUpperCase()) != -1);

        bgListToLetter.forEach((_, idx) => {
            const bgNode = cc.find(`Canvas/LetterPicturePage/BgNode_${idx}`);
            bgNode.active = idx == showBgIdx;
        });

        const letterWordMap = {
            a: { big: '<color=#73edff>A</c><color=#ffffff>PPLE</color>', small: '<color=#abff61>a</c><color=#ffffff>pple</color>' },
            b: { big: '<color=#73edff>B</c><color=#ffffff>AG</color>', small: '<color=#abff61>b</c><color=#ffffff>ag</color>' },
            c: { big: '<color=#73edff>C</c><color=#ffffff>AT</color>', small: '<color=#abff61>c</c><color=#ffffff>at</color>' },
            d: { big: '<color=#73edff>D</c><color=#ffffff>OG</color>', small: '<color=#abff61>d</c><color=#ffffff>og</color>' },
            e: { big: '<color=#73edff>E</c><color=#ffffff>GG</color>', small: '<color=#abff61>e</c><color=#ffffff>gg</color>' },
            f: { big: '<color=#73edff>F</c><color=#ffffff>LOWER</color>', small: '<color=#abff61>f</c><color=#ffffff>lower</color>' },
            g: { big: '<color=#73edff>G</c><color=#ffffff>IRL</color>', small: '<color=#abff61>g</c><color=#ffffff>irl</color>' },
            h: { big: '<color=#73edff>H</c><color=#ffffff>AT</color>', small: '<color=#abff61>h</c><color=#ffffff>at</color>' },
            i: { big: '<color=#73edff>I</c><color=#ffffff>NK</color>', small: '<color=#abff61>i</c><color=#ffffff>nk</color>' },
            j: { big: '<color=#73edff>J</c><color=#ffffff>AM</color>', small: '<color=#abff61>j</c><color=#ffffff>am</color>' },
            k: { big: '<color=#73edff>K</c><color=#ffffff>EY</color>', small: '<color=#abff61>k</c><color=#ffffff>ey</color>' },
            l: { big: '<color=#73edff>L</c><color=#ffffff>ION</color>', small: '<color=#abff61>l</c><color=#ffffff>ion</color>' },
            m: { big: '<color=#73edff>M</c><color=#ffffff>ONKEY</color>', small: '<color=#abff61>m</c><color=#ffffff>onkey</color>' },
            n: { big: '<color=#73edff>N</c><color=#ffffff>OODLES</color>', small: '<color=#abff61>n</c><color=#ffffff>oodles</color>' },
            o: { big: '<color=#73edff>O</c><color=#ffffff>RANGE</color>', small: '<color=#abff61>o</c><color=#ffffff>range</color>' },
            p: { big: '<color=#73edff>P</c><color=#ffffff>ANDA</color>', small: '<color=#abff61>p</c><color=#ffffff>anda</color>' },
            q: { big: '<color=#73edff>Q</c><color=#ffffff>UEEN</color>', small: '<color=#abff61>q</c><color=#ffffff>ueen</color>' },
            r: { big: '<color=#73edff>R</c><color=#ffffff>ABBIT</color>', small: '<color=#abff61>r</c><color=#ffffff>abbit</color>' },
            s: { big: '<color=#73edff>S</c><color=#ffffff>WAN</color>', small: '<color=#abff61>s</c><color=#ffffff>wan</color>' },
            t: { big: '<color=#73edff>T</c><color=#ffffff>IGER</color>', small: '<color=#abff61>t</c><color=#ffffff>iger</color>' },
            u: { big: '<color=#73edff>U</c><color=#ffffff>MBRELLA</color>', small: '<color=#abff61>u</c><color=#ffffff>mbrella</color>' },
            v: { big: '<color=#73edff>V</c><color=#ffffff>IOLIN</color>', small: '<color=#abff61>v</c><color=#ffffff>iolin</color>' },
            w: { big: '<color=#73edff>W</c><color=#ffffff>INDOW</color>', small: '<color=#abff61>w</c><color=#ffffff>indow</color>' },
            x: { big: '<color=#ffffff>BO</color><color=#73edff>X</c>', small: '<color=#ffffff>bo</color><color=#abff61>x</c>' },
            y: { big: '<color=#73edff>Y</c><color=#ffffff>OGURT</color>', small: '<color=#abff61>y</c><color=#ffffff>ogurt</color>' },
            z: { big: '<color=#73edff>Z</c><color=#ffffff>EBRA</color>', small: '<color=#abff61>z</c><color=#ffffff>ebra</color>' }
        }

        const bigPictureWordRichText = cc.find('Canvas/LetterPicturePage/PictureWordBigBg/PictureWordBigRichText');
        bigPictureWordRichText.getComponent(cc.RichText).string = letterWordMap[this.letter.toLowerCase()].big;
        const pictureWordSmallRichText = cc.find('Canvas/LetterPicturePage/PictureWordSmallBg/PictureWordSmallRichText');
        pictureWordSmallRichText.getComponent(cc.RichText).string = letterWordMap[this.letter.toLowerCase()].small;

        const letterPictureBase = cc.find('Canvas/LetterPicturePage/LetterPicture');
        letterPictureBase.children.forEach(node => node.active = false);
        const letterPictureNode = cc.find(`Canvas/LetterPicturePage/LetterPicture/bg_${this.letter.toLowerCase()}`);
        letterPictureNode.active = true;
        letterPictureNode.addComponent(cc.Button);
        letterPictureNode.on('click', () => {
            jelly(letterPictureNode);
            this.playEffect(`word${this.letter.toUpperCase()}`);
        });

        const changeToBig = cc.find('Canvas/LetterPicturePage/BtnSwitch/ChangeToBig');
        const changeToSmall = cc.find('Canvas/LetterPicturePage/BtnSwitch/ChangeToSmall');

        const smallLetterBase = cc.find('Canvas/LetterPicturePage/SmallLetterBase');
        const bigLetterBase = cc.find('Canvas/LetterPicturePage/BigLetterBase');

        const pictureWordSmallBg = cc.find('Canvas/LetterPicturePage/PictureWordSmallBg');
        const pictureWordBigBg = cc.find('Canvas/LetterPicturePage/PictureWordBigBg');

        changeToBig.active = false;
        changeToSmall.active = true;
        smallLetterBase.active = false;
        bigLetterBase.active = true;
        pictureWordSmallBg.active = false;
        pictureWordBigBg.active = true;

        const btnBefore = cc.find('Canvas/LetterPicturePage/BtnBefore');
        const btnNext = cc.find('Canvas/LetterPicturePage/BtnNext');

        btnBefore.active = true;
        btnNext.active = true;

        if (this._status.currentLetterIdx == 0) {
            btnBefore.active = false;
        }
        if (this._status.currentLetterIdx == this.data.letterList.length - 1) {
            btnNext.active = false;
        }

        btnNext.stopAllActions();
        cc.tween(btnNext)
            .call(() => {
                for (let i = 0; i < 3; i++) {
                    const imgBtnBg = cc.instantiate(cc.find('Canvas/LetterPicturePage/BtnNext/ImgBtnBg'));
                    imgBtnBg.parent = btnNext;
                    imgBtnBg.zIndex = 3 - i;
                    imgBtnBg.opacity = 100;
                    cc.tween(imgBtnBg)
                        .delay(0.2 * i)
                        .to(1, { scaleX: 1.5, scaleY: 1.5, opacity: 0 })
                        .call(() => {
                            imgBtnBg.stopAllActions();
                            imgBtnBg.removeFromParent();
                        })
                        .start();
                }
            })
            .delay(3)
            .union()
            .repeatForever()
            .start();
    },

    createLetterPage(letter) {
        this._status.currentStrokeIdx = 0;
        this._status.currentStrokeStageIdx = 0;

        const letterNodeBase = cc.instantiate(this[`letter${letter}Prefab`]);
        letterNodeBase.name = 'letterNodeBase';
        letterNodeBase.parent = this.node;

        const btnUpdate = letterNodeBase.getChildByName('BtnUpdate');
        btnUpdate.on('click', () => {
            this.drawCompleteLine(this._status.currentStrokeIdx);
            this._status.currentStrokeIdx++;
            if (this._status.currentStrokeIdx >= 4) {
                this._status.currentStrokeIdx = 0;
            }
            this.updateArrows(this._status.currentStrokeIdx);
        });
        btnUpdate.active = false;
        this.updateArrows(this._status.currentStrokeIdx);

        // this.drawCompleteLine(this._status.currentStrokeIdx);

        const letterPageUINode = cc.instantiate(this.letterPageUINode);
        letterPageUINode.name = 'letterPageUINode';
        letterPageUINode.parent = letterNodeBase;

        const speakerNode = letterPageUINode.getChildByName('SpeakerNode');
        speakerNode.on('click', async () => {
            this.startSpeakerAnime(speakerNode);

            await this.playEffect(`letter${this.letter}`);

            this.stopSpeakerAnime(speakerNode);
        });

        let showMonkey = false;
        if ('abcdefghijklmnopqrstuvwxyz'.indexOf(letter) !== -1) {
            showMonkey = true;
        }
        const pos0 = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_0_0`);
        this.createShark(pos0, this.getSharkAngle(0, 0), showMonkey);

        this.node.getComponent(cc.Widget).updateAlignment();
        letterNodeBase.scaleX = this.node.height / 720;
        letterNodeBase.scaleY = this.node.height / 720;

        const bgNode = cc.instantiate(this.bgNode);
        bgNode.parent = letterNodeBase;
        bgNode.zIndex = -1;
        bgNode.width = this.node.width / letterNodeBase.scaleY;

        bgNode.addComponent(cc.Button);
        bgNode.on('click', () => { });

        if (letter !== letter.toLowerCase()) {
            bgNode.getChildByName('BgLower').active = false;
        }

        if (letter == letter.toLowerCase()) {
            const monkeyUpperNode = cc.instantiate(this.monkeyUpperNode);
            monkeyUpperNode.parent = letterNodeBase;
            monkeyUpperNode.scaleX = 720 / this.node.height;
            monkeyUpperNode.scaleY = 720 / this.node.height;
            monkeyUpperNode.y = -letterNodeBase.height / 2;
        }

        const drawMaskNode = cc.find('Canvas/letterNodeBase/DrawMaskNode');
        const letterNode = cc.find('Canvas/letterNodeBase/bg_a');
        // drawMaskNode.scaleX = letterNodeBase.height / 720;
        // drawMaskNode.scaleY = letterNodeBase.height / 720;
        // letterNode.scaleX = letterNodeBase.height / 720;
        // letterNode.scaleY = letterNodeBase.height / 720;
    },

    startSpeakerAnime(speakerBase) {
        const speakers = [];
        for (let index = 0; index < 3; index++) {
            const node = cc.find(`Canvas/letterNodeBase/letterPageUINode/SpeakerNode/SpeakerNode_${index}`);
            speakers.push(node);
        }
        let currentIdx = 0;
        cc.tween(speakerBase)
            .call(() => {
                speakers.forEach(node => node.active = false);
                speakers[currentIdx % speakers.length].active = true;
                currentIdx++;
            })
            .delay(0.2)
            .union()
            .repeatForever()
            .start();
    },

    stopSpeakerAnime(speakerBase) {
        speakerBase.stopAllActions();
        for (let index = 0; index < 3; index++) {
            const node = cc.find(`Canvas/letterNodeBase/letterPageUINode/SpeakerNode/SpeakerNode_${index}`);
            node.active = false;
        }
        const node0 = cc.find(`Canvas/letterNodeBase/letterPageUINode/SpeakerNode/SpeakerNode_0`);
        node0.active = true;
    },

    getPosListByStrokeIdx(strokeIdx) {
        let stepIdx = 0;
        let pos0 = null;
        const drawMaskNode = cc.find('Canvas/letterNodeBase/DrawMaskNode');
        const posList = [];
        do {
            pos0 = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_${strokeIdx}_${stepIdx}`);
            stepIdx++;

            if (pos0) {
                posList.push({
                    x: pos0.x,
                    y: pos0.y
                });
            }
        } while (pos0);
        return posList;
    },

    getCurrentCheckPos() {
        const letterNodeBase = cc.find(`Canvas/letterNodeBase`);
        const nodePosBase = cc.find('Canvas/letterNodeBase/NodePosBase');
        let pos1 = nodePosBase.getChildByName(`NodePos_${this._status.currentStrokeIdx}_${this._status.currentStrokeStageIdx}`);
        let pos2 = nodePosBase.getChildByName(`NodePos_${this._status.currentStrokeIdx}_${this._status.currentStrokeStageIdx + 1}`);
        if (pos2) {
            return [
                { x: pos1.x, y: pos1.y },
                { x: pos2.x, y: pos2.y }
            ];
        }
        return null;
    },

    updateArrows(idx) {
        const nodePosBase = cc.find(`Canvas/letterNodeBase/NodePosBase`);

        if (this.arrowPrefabList) {
            this.arrowPrefabList.forEach(node => {
                node.parent = null;
            });
        }
        this.arrowPrefabList = [];

        for (let i = 0; i < 5; i++) {
            let startNode = nodePosBase.getChildByName(`NodePos_${i}_0`);
            if (!startNode) {
                break;
            }
            this.createStep(startNode, nodePosBase, i, idx);
        }
    },

    createStep(startNode, nodePosBase, stepIdx, idx) {

        startNode.opacity = 0;
        let lastNode = startNode;
        for (let j = 1; j < 100; j++) {
            let endNode = nodePosBase.getChildByName(`NodePos_${stepIdx}_${j}`);
            if (!endNode) {
                break;
            }
            endNode.opacity = 0;

            this.createArrows(endNode, lastNode, stepIdx, j, idx);
            lastNode = endNode;
        }
        if (stepIdx == idx) {
            this.createStar(lastNode);
        }
    },

    createArrows(endNode, lastNode, skipIdx, stepIdx, idx) {

        let letterNodeBase = cc.find(`Canvas/letterNodeBase`)
        const lineVec2 = cc.v2(endNode.x - lastNode.x, endNode.y - lastNode.y);
        const lineLength = lineVec2.mag();
        const arrowNumber = Math.ceil(lineLength / 100);
        for (let k = 0; k < arrowNumber; k++) {
            if (skipIdx != idx) {
                continue;
            }

            const arrowPrefab = cc.instantiate(this.arrowPrefab);

            arrowPrefab.x = lastNode.x + lineVec2.x * (k + 1) / (arrowNumber + 1);
            arrowPrefab.y = lastNode.y + lineVec2.y * (k + 1) / (arrowNumber + 1);
            arrowPrefab.angle = cc.v2(1, 0).signAngle(lineVec2) * 180 / Math.PI;
            // arrowPrefab.name = name;
            arrowPrefab.parent = letterNodeBase;
            this.arrowPrefabList.push(arrowPrefab);

            const nodeArrow = arrowPrefab.getChildByName('NodeArrow');
            cc.tween(nodeArrow)
                .delay((stepIdx + k) * 0.3)
                .to(0.2, { opacity: 0 })
                .delay(0.5)
                .to(0.2, { opacity: 255 })
                .delay(7 - (stepIdx + k) * 0.3)
                .union()
                .repeatForever()
                .start();
        }
    },

    createShark(startNode, angle, monkey = false) {
        let letterNodeBase = cc.find(`Canvas/letterNodeBase`)
        let sharkNode = null;
        if (!this.sharkNode) {
            this.sharkNode = cc.instantiate(this.sharkPreFab);
            this.sharkNode.parent = letterNodeBase;
            this.sharkNode.zIndex = 2;
            this.sharkNode.x = startNode.x;
            this.sharkNode.y = startNode.y;
            this.addSharkListeners();
        }
        sharkNode = this.sharkNode.getChildByName('SharkNode');
        sharkNode.angle = angle;
        sharkNode.active = !monkey;

        const monkeyNode = this.sharkNode.getChildByName('MonkeyNode');
        monkeyNode.active = monkey;

        cc.tween(this.sharkNode)
            .to(0.1, { x: startNode.x, y: startNode.y })
            .start();
        cc.tween(sharkNode)
            .to(0.1, { angle: angle })
            .start();
    },

    onSharkMoveStart(event) {
        jelly(this.sharkNode);
        this.sharkNode.startPos = event.getLocation();
        this.playEffect('按住');
        this.onDrawStart(event);
        this.onSharkMoving(event);
    },

    onSharkMoving(event) {
        if (!this.sharkNode) {
            return;
        }
        const startPos = this.sharkNode.startPos;
        if (!startPos) {
            return;
        }
        const location = event.getLocation();
        const currentPosList = this.getCurrentCheckPos();
        if (!currentPosList) {
            return;
        }
        const letterNodeBase = cc.find(`Canvas/letterNodeBase`);

        const [pos1, pos2] = currentPosList;
        const checkLine = cc.v2(pos2.x - pos1.x, pos2.y - pos1.y);

        const locationPos = letterNodeBase.convertToNodeSpaceAR(location);
        this.sharkNode.x = locationPos.x;
        this.sharkNode.y = locationPos.y;

        const trueSharkNode = this.sharkNode.getChildByName('SharkNode');

        let angle = cc.v2(1, 0).signAngle(checkLine) * 180 / Math.PI;
        if (angle - trueSharkNode.angle < -180) {
            angle += 360;
        }
        if (angle - trueSharkNode.angle > 180) {
            angle -= 360;
        }

        if (!this.sharkNode.angleAction) {
            this.sharkNode.angleAction = true;
            cc.tween(trueSharkNode)
                .to(0.2, { angle: angle })
                .call(() => {
                    this.sharkNode.angleAction = false;
                })
                .start();
        }

        if (this.checkPointInCircle(this.sharkNode, pos2, 130)) {
            this._status.currentStrokeStageIdx++
            if (this.getCurrentCheckPos() === null) {
                this.drawCompleteLine(this._status.currentStrokeIdx);
                this.showStar();
                this._status.currentStrokeIdx++;
                this._status.currentStrokeStageIdx = 0;
                if (this.getCurrentCheckPos() === null) {
                    this.showOver();
                }
                this.updateArrows(this._status.currentStrokeIdx);
                // this.onSharkMoveEnd(event);
            }
        }

        const posList = this.getPosListByStrokeIdx(this._status.currentStrokeIdx);
        if (!this.checkPointInRangeList(letterNodeBase.convertToNodeSpaceAR(location), posList, 50)) {
            this._status.currentStrokeStageIdx = 0;
            this.onSharkMoveEnd(event);
            return;
        }

        this.onDrawMove(event);
    },

    getSharkAngle(currentStrokeIdx, currentStrokeStageIdx) {
        let pos1 = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_${currentStrokeIdx}_${currentStrokeStageIdx}`);
        let pos2 = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_${currentStrokeIdx}_${currentStrokeStageIdx + 1}`);
        const line = cc.v2(pos2.x - pos1.x, pos2.y - pos1.y);
        return cc.v2(1, 0).signAngle(line) * 180 / Math.PI;
    },

    onSharkMoveEnd(event) {
        let pos = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_${this._status.currentStrokeIdx}_0`);
        if (!pos) {
            return;
        }
        this._status.currentStrokeStageIdx = 0;

        cc.tween(this.sharkNode)
            .to(0.1, { x: pos.x, y: pos.y })
            .start();

        cc.tween(this.sharkNode.getChildByName('SharkNode'))
            .to(0.1, { angle: this.getSharkAngle(this._status.currentStrokeIdx, 0) })
            .start();

        this.sharkNode.startPos = null;
        this.onDrawEnd(event);
    },

    addSharkListeners() {
        this.sharkNode.on('touchstart', this.onSharkMoveStart, this);
        this.sharkNode.on('touchmove', this.onSharkMoving, this);
        this.sharkNode.on('touchend', this.onSharkMoveEnd, this);
        this.sharkNode.on('touchcancel', this.onSharkMoveEnd, this);
    },

    hideShark() {
        cc.tween(this.sharkNode)
            .to(0.3, { opacity: 0 })
            .call(() => {
                this.sharkNode.parent = null;
                this.sharkNode = null;
            })
            .start();
    },

    async showOver() {
        this.hideShark();
        this.playEffect('放大');
        await this.showCompleteStar();
        this.playEffect(`letter${this.letter}`);
        await this.showRibbons();
        this.playEffect('撒花');
        await this.showCloud();
        this.pageFlyOut();
        if (this.letter !== this.letter.toLowerCase()) {
            this.letter = this.letter.toLowerCase();
            this.createLetterPage(this.letter);
        } else {
            if (this._status.currentLetterIdx == this.data.letterList.length - 1) {

                if (wx) {
                    this.getUserInfo();
                } else {
                    this.showScrollView();
                }


            }
        }
    },

    async showCompleteStar() {
        return new Promise((resolve, reject) => {
            this.starNode.zIndex = 10;
            cc.tween(this.starNode)
                .to(0.1, { opacity: 255 })
                .to(1, { x: 0, y: 0, scale: 3 })
                .to(1, { scale: 6, opacity: 0 })
                .call(resolve)
                .start();
        })
    },

    async showCloud() {
        const cloudPosList = [];
        const posList = this.getCloudPosList();
        posList.forEach(stepList => {
            // stepList
            for (let i = 0; i < stepList.length - 1; i++) {
                const pos0 = stepList[i];
                const pos1 = stepList[i + 1];

                const line = cc.v2(pos1.x - pos0.x, pos1.y - pos0.y);
                cloudPosList.push(pos0);
                if (line.mag() > 150) {
                    const length = Math.ceil(line.mag() / 80);
                    for (let j = 1; j < length; j++) {
                        const newLine = line.mul(j / length);
                        cloudPosList.push({ x: newLine.x + pos0.x, y: newLine.y + pos0.y });
                    }
                }
            }
            cloudPosList.push(stepList[stepList.length - 1]);
        });

        await Promise.all(cloudPosList.map(async (pos, idx) => {
            await this.createCloud(pos, idx);
        }));
    },

    createCloud({ x, y }, idx) {
        return new Promise((resolve, reject) => {
            const letterNodeBase = cc.find(`Canvas/letterNodeBase`);
            const cloud = cc.instantiate(this.cloudPrefab);
            cloud.parent = letterNodeBase;
            cloud.x = x;
            cloud.y = y;
            cloud.scale = 0;

            cc.tween(cloud)
                .delay(idx * 0.1)
                .to(0.2, { scale: 1.2 })
                .to(0.05, { scale: 1 })
                .call(resolve)
                .start();
        });
    },

    getCloudPosList() {
        const posList = [];
        do {
            let currentPosList = [];
            let currentStepIdx = posList.length;
            let currentPosIdx = 0;
            do {
                let pos = cc.find(`Canvas/letterNodeBase/NodePosBase/NodePos_${currentStepIdx}_${currentPosIdx}`);
                if (!pos) {
                    break;
                }
                currentPosIdx++;
                currentPosList.push({ x: pos.x, y: pos.y });
            } while (true);

            if (currentPosList.length == 0) {
                break;
            }
            posList.push(currentPosList);
        } while (true);

        return posList;
    },

    pageFlyOut() {
        const letterNodeBase = cc.find(`Canvas/letterNodeBase`);
        letterNodeBase.name = 'letterNodeBase0';
        letterNodeBase.zIndex = 10;
        cc.tween(letterNodeBase)
            .to(1.2, { y: 1500 }, { easing: 'cubicIn' })
            .call(() => {
                letterNodeBase.active = false;
            })
            .start();
    },

    createStar(endNode) {
        const letterNodeBase = cc.find(`Canvas/letterNodeBase`);
        if (this.starNode) {
            this.starNode.parent = null;
            this.starNode = null;
        }
        const starNode = cc.instantiate(this.starPreFab);
        starNode.parent = letterNodeBase;
        starNode.x = endNode.x;
        starNode.y = endNode.y;
        this.starNode = starNode;
    },

    async showStar() {
        let starAnimeNode = cc.instantiate(this.starAnimePrefab);
        starAnimeNode.parent = this.node;
        starAnimeNode.x = this.starNode.x;
        starAnimeNode.y = this.starNode.y;
        starAnimeNode.zIndex = 10;

        cc.tween(this.starNode)
            .to(0.1, { opacity: 0 })
            .start();

        this.playEffect('star');

        await asyncPlayDragonBoneAnimation(starAnimeNode, 'star', 1);
        starAnimeNode.parent = null;
        starAnimeNode = null;
    },

    async showRibbons() {
        for (let i = 0; i < 50; i++) {
            const ribbonNodeBase = cc.instantiate(cc.find('Canvas/RibbonNodeBase'));
            ribbonNodeBase.parent = this.node;
            ribbonNodeBase.y = 400 + RandomInt(720);
            ribbonNodeBase.zIndex = 10;
            ribbonNodeBase.x = RandomInt(-720, 720);
            ribbonNodeBase.angle = RandomInt(360);

            const ribbonNode = ribbonNodeBase.getChildByName(`RibbonNode_${RandomInt(4)}`);
            ribbonNode.active = true;

            cc.tween(ribbonNodeBase)
                .by(3, { y: -1600, x: RandomInt(-100, 100), angle: RandomInt(-60, 60) })
                .call(() => {
                    ribbonNodeBase.active = false;
                    ribbonNodeBase.removeFromParent();
                })
                .start();
        }
    },

    drawCompleteLine(strokeIdx) {
        const drawGraphyNode = cc.find('Canvas/letterNodeBase/DrawMaskNode/DrawGraphyNodeBase');
        this.drawLines(drawGraphyNode, this.getPosListByStrokeIdx(strokeIdx));
    },

    drawLines(drawNode, posList) {
        const graph = drawNode.getComponent(cc.Graphics);
        posList.forEach((pos, idx) => {
            if (idx == 0) {
                graph.moveTo(pos.x, pos.y);
                return;
            }
            graph.lineTo(pos.x, pos.y);
        });
        graph.stroke();
    },

    onDrawStart(event) {
        const drawGraphyNode = cc.find('Canvas/letterNodeBase/DrawMaskNode/DrawGraphyNodeCurrent')
        const graph = drawGraphyNode.getComponent(cc.Graphics);
        const location = event.getLocation();
        const pos = drawGraphyNode.convertToNodeSpaceAR(location);
        graph.moveTo(pos.x, pos.y);
    },

    onDrawMove(event) {
        if (!this._moveCount) {
            this._moveCount = 0;
        }
        this._moveCount++;
        if (this._moveCount < 5) {
            return;
        }
        this._moveCount = 0
        const drawGraphyNode = cc.find('Canvas/letterNodeBase/DrawMaskNode/DrawGraphyNodeCurrent')
        const graph = drawGraphyNode.getComponent(cc.Graphics);
        graph.lineWidth = 120;
        const location = event.getLocation();
        const pos = drawGraphyNode.convertToNodeSpaceAR(location);

        if (!this._lastPos) {
            this._lastPos = { x: pos.x, y: pos.y };
        } else {
            const offsetX = pos.x - this._lastPos.x;
            const offsetY = pos.y - this._lastPos.y;
            if ((-10 < offsetX && offsetX < 10) && (-10 < offsetY && offsetY < 10)) {
                return;
            }
            this._lastPos = { x: pos.x, y: pos.y };
        }

        graph.lineTo(pos.x, pos.y);
        graph.stroke();
    },

    onDrawEnd(event) {
        const drawGraphyNode = cc.find('Canvas/letterNodeBase/DrawMaskNode/DrawGraphyNodeCurrent')
        const graph = drawGraphyNode.getComponent(cc.Graphics);
        graph.clear();
        this._lastPos = null;
    },

    addDrawListeners() {
        const drawGraphyNode = cc.find('Canvas/letterNodeBase/DrawMaskNode/DrawGraphyNodeCurrent');
        drawGraphyNode.on('touchstart', this.onDrawStart, this);
        drawGraphyNode.on('touchmove', this.onDrawMove, this);
        drawGraphyNode.on('touchend', this.onDrawEnd, this);
        drawGraphyNode.on('touchcancel', this.onDrawEnd, this);
    },

    checkPointInCircle(pos, center, radius) {
        const line = cc.v2(pos.x - center.x, pos.y - center.y);
        if (line.mag() > radius) {
            return false;
        }
        return true;
    },

    checkPointInRangeList(pos, rangePosList, radius) {
        let inRange = false;
        rangePosList.forEach((rangePos, idx) => {
            if (idx == 0) {
                return;
            }
            inRange = inRange || this.checkPointInRange(pos, rangePosList[idx - 1], rangePos, radius);
        });
        return inRange;
    },

    checkPointInRange(pos, rangePos1, rangePos2, radius) {
        const linePos2 = cc.v2(rangePos2.x - rangePos1.x, rangePos2.y - rangePos1.y);
        const linePos = cc.v2(pos.x - rangePos1.x, pos.y - rangePos1.y);
        const angle = linePos2.signAngle(linePos);
        const distance = linePos.mag() * Math.sin(angle);
        // 如果pos点到pos1与pos2连线的距离大于半径，则超出
        if (distance > radius || distance < - radius) {
            return false;
        }
        const projection = linePos.mag() * Math.cos(angle);
        // 如果pos1到pos点的向量到pos1到pos2的向量投影长度超出范围
        if (projection < - radius || projection > radius + linePos2.mag()) {
            return false;
        }

        return true;
    },

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



    svItemArr: null,
    rankLineH: null,
    rankTopH: null,
    nameLabel: null,
    scoreLabel: null,
    finishLabel: null,
    startTime: null,
    rankLabel: null,
    rankData: null,
    initScrollView() {

        this.receiveData(this.courseid, (rankData) => {
            this.rankData = rankData;
        });


        this.svItemArr = [];
        this.topH = 60;
        this.rankLineH = 60;
        this.startTime = new Date().getTime();

        const sv = cc.find('Canvas/scrollview');
        sv.zIndex = 11;

        const content = cc.find('Canvas/scrollview/view/content')

        const titleLabel = this.getLabel();
        titleLabel.string = '榜单'
        titleLabel.node.parent = content;
        titleLabel.node.y = -40;
        titleLabel.fontSize = 40;

        const w = content.width * 0.9;

        const lineRow = this.getLine(w, 5);
        lineRow.node.parent = content;
        lineRow.node.y = titleLabel.node.y - 30;
        lineRow.node.x = -w / 2;

        const rankLabel = this.getLabel();
        rankLabel.string = '排名';
        rankLabel.node.x = -w / 2;
        rankLabel.node.y = -this.topH - this.rankLineH;
        rankLabel.node.anchorX = 0;
        rankLabel.node.parent = content;
        rankLabel.fontSize = 30;
        this.rankLabel = rankLabel;

        const nameLabel = this.getLabel();
        nameLabel.string = '姓名';
        nameLabel.node.x = -w / 4;
        nameLabel.node.y = -this.topH - this.rankLineH;
        nameLabel.node.parent = content;
        nameLabel.fontSize = 30;
        this.nameLabel = nameLabel;


        const scoreLabel = this.getLabel();
        scoreLabel.string = '时长';
        scoreLabel.node.x = w / 10;
        scoreLabel.node.y = nameLabel.node.y
        scoreLabel.node.parent = content;
        scoreLabel.fontSize = 30;
        this.scoreLabel = scoreLabel;

        const finishLabel = this.getLabel();
        finishLabel.string = '完成时间';
        finishLabel.node.x = w / 2;
        finishLabel.node.y = nameLabel.node.y
        finishLabel.node.anchorX = 1;
        finishLabel.node.parent = content;
        finishLabel.fontSize = 30;
        this.finishLabel = finishLabel;

    },

    initReplayBtn() {

        const replayBtn = cc.find('Canvas/replayButton');
        replayBtn.zIndex = 11;
        replayBtn.on('click', () => {

            cc.assetManager.loadBundle('tmpGame/scene_2', (err, bundle) => {

                bundle.loadScene('n_xuan1', (err, s) => {
                    cc.director.runScene(s);
                })
            })
        })
    },

    setScrollView() {

        const rankData = this.rankData
        console.log('rankData: ', rankData);
        for (let i = 0; i < rankData.length; i++) {
            this.addScrollViewItem(rankData[i], i + 1);
        }
    },

    addScrollViewItem(data, rank) {

        const contentH = 450;
        const topH = this.rankTopH + this.rankLineH;;
        const content = cc.find('Canvas/scrollview/view/content')

        this.svItemArr.push(data);

        let fontColor = cc.Color.BLACK;
        if (data.name == this.userInfo.nickName) {
            fontColor = cc.Color.BLUE;
        }

        const rankLabel = this.getLabel();
        rankLabel.node.color = fontColor;
        rankLabel.string = rank
        rankLabel.node.parent = content;
        rankLabel.node.x = this.rankLabel.node.x + 30;
        rankLabel.node.y = -(this.svItemArr.length + 1) * this.rankLineH - topH;
        const h = Math.max(-rankLabel.node.y, contentH) + 10;
        content.height = h

        const nameLabel = this.getLabel();
        nameLabel.node.color = fontColor;
        nameLabel.string = data.name; // '玩家-' + (this.svItemArr.length);
        nameLabel.node.parent = content;
        nameLabel.node.x = this.nameLabel.node.x;
        nameLabel.node.y = rankLabel.node.y;

        const scoreLabel = this.getLabel();
        scoreLabel.node.color = fontColor;
        scoreLabel.string = formatSeconds(data.score / 1000)// '分数-' + (this.svItemArr.length);
        scoreLabel.node.parent = content;
        scoreLabel.node.x = this.scoreLabel.node.x;
        scoreLabel.node.y = nameLabel.node.y;

        const finishLabel = this.getLabel();
        finishLabel.node.color = fontColor;
        // finishLabel.string = '时间-' + (this.svItemArr.length);
        // const dateTime = new Date().getTime();
        finishLabel.string = dateFormat('YYYY-mm-dd HH:MM', new Date(data.date))
        finishLabel.node.parent = content;
        finishLabel.node.anchorX = 1;
        finishLabel.node.x = this.finishLabel.node.x;
        finishLabel.node.y = nameLabel.node.y;

        const lineRow = this.getLine(content.width * 0.9, 2);
        lineRow.node.parent = content;
        lineRow.node.y = nameLabel.node.y + 40;
        lineRow.node.x = -content.width * 0.9 / 2;
    },

    showScrollView() {

        const curTime = new Date().getTime();
        const scoreTime = curTime - this.startTime;
        const id = this.getUserId();
        const newData = {
            courseid: this.courseid,
            id: 1,
            name: this.userInfo.nickName,
            score: scoreTime,
            date: curTime
        }

        const rankData = this.rankData;

        let isNeedSendData = true;
        rankData.forEach((item, i) => {
            if (item.name == newData.name) {

                if (item.score < newData.score) {
                    isNeedSendData = false;
                }
            }
        })
        if (isNeedSendData) {
            rankData.push(newData);
            this.sendData(newData);
        }




        const tmpData = {}
        for (let i = 0; i < rankData.length; i++) {
            const scoreData = rankData[i];
            if (!tmpData[scoreData.name]) {
                tmpData[scoreData.name] = scoreData
            } else {
                if (tmpData[scoreData.name].score > scoreData.score) {
                    tmpData[scoreData.name] = scoreData;
                }
            }
        }

        const newRankData = [];
        for (let key in tmpData) {
            newRankData.push(tmpData[key])
        }
        newRankData.sort((a, b) => {
            return Number(a.score) - Number(b.score);
        })
        this.rankData = newRankData;


        this.setScrollView();

        cc.find('Canvas/scrollview').active = true;

    },
    sendData(data) {

        http('POST', 'https://staging-teach.ireadabc.com/api/dashboard/v1/studyinfo?courseid=' + this.courseid, data).then((resStr) => {
            const res = JSON.parse(resStr)
            console.log(' sendData res: ', res);
        });

    },
    receiveData(id, cb) {

        http('GET', 'https://staging-teach.ireadabc.com/api/dashboard/v1/studyinfo?courseid=' + this.courseid, {}).then((resStr) => {
            const res = JSON.parse(resStr)
            if (cb) {
                cb(res.data);
            }
            console.log(' receiveData res: ', res.data);
        });

        // let strData = localStorage.getItem(id);
        // if (!strData) {
        //     strData = '[]'
        // }
        // return JSON.parse(strData);
    },
    getLabel() {
        const node = new cc.Node();
        const label = node.addComponent(cc.Label);
        node.color = cc.Color.BLACK;
        label.fontSize = 20;

        return label;
    },
    getLine(w, h) {
        const node = new cc.Node();
        const line = node.addComponent(cc.Graphics);
        line.fillColor = '#cccccc';
        line.rect(0, 0, w, h)
        line.fill();
        return line;
    },
    getUserId() {
        return Math.floor(Math.random() * 100) + 1;
    },
    userInfo: null,
    getUserInfo() {

        console.log(' in getUserInfo 1')
        if (!wx) {
            console.log('no wx');
            return;
        }
        if (!wx) {
            console.log('no window.wx')
            return;
        }

        console.log(' in getUserInfo 2')

        const self = this;
        self.createUserInfoButton();



    },

    showLoadingPage() {
        const loading = cc.find('Canvas/loading')
        const loadingBg = loading.getChildByName('bg');
        const loadingIcon = loading.getChildByName('icon');
        loading.opacity = 255;
        loading.active = true;
        loading.zIndex = 15;

        loadingBg.width = cc.winSize.width;
        loadingBg.height = cc.winSize.height;

        loadingIcon.opacity = 0;
        cc.tween(loadingIcon)
            .to(2, { opacity: 255 }, { easing: 'cubicOut' })
            .start()
    },

    hideLoadingPage() {
        const loading = cc.find('Canvas/loading')

        cc.tween(loading)
            .to(0.5, { opacity: 0 }, { easing: 'cubicOut' })
            .call(() => {
                loading.active = false;
            })
            .start()
    },

    /**
   * 点击创建用户信息授权按钮
   */
    authorButton: null,
    createUserInfoButton() {
        //获取视图窗口可见区域尺寸
        let visibleSize = cc.view.getVisibleSize();
        //获取系统信息
        let wx_size = wx.getSystemInfoSync();
        //计算实际大小和可见区域尺寸的比例（这里以宽度为准）
        let size_scale_width = wx_size.screenWidth / visibleSize.width;
        //计算创建用户信息按钮需要的属性（img_auth为蓝色参考节点）
        let x = visibleSize.width / 2; //(this.img_auth.x + visibleSize.width / 2 - this.img_auth.width / 2) * size_scale_width;
        let y = visibleSize.height / 2; // (Math.abs(this.img_auth.y) + visibleSize.height / 2 - this.img_auth.height / 2) * size_scale_width;
        let width = 300; // this.img_auth.width * size_scale_width;
        let height = 300; // this.img_auth.height * size_scale_width;


        const frameSize = cc.view.getFrameSize();
        const rankBtnW = 200;
        const rankBtnH = 40;

        const disH = -40;

        this.authorButton = wx.createUserInfoButton({
            type: 'text',
            text: '查看排行',
            style: {
                left: frameSize.width / 2 - rankBtnW / 2,
                top: frameSize.height / 2 - rankBtnH / 2 - disH,
                width: 200,
                height: 40,
                lineHeight: 40,
                backgroundColor: '#cccccc',
                color: '#222222',
                textAlign: 'center',
                fontSize: 16,
                borderRadius: 4
            }
        })

        const replayBtn = cc.find('Canvas/replayButton');
        // replayBtn.y = cc.winSize.height / 2 - disH;
        replayBtn.active = true;


        console.log('this.authorButton: ', this.authorButton);
        this.authorButton.onTap((res) => {
            if (res.errMsg == "getUserInfo:ok") {
                wx.showToast({
                    icon: "none",
                    title: "获取用户信息成功",
                    duration: 2000,
                });
                this.authorButton.hide(); //获取用户信息成功后隐藏按钮

                // wx.login({
                //     success (res) {
                //         console.log('login res: ', res);
                //       if (res.code) {
                //         //发起网络请求

                //         const tmpUrl = 'https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code'
                //         wx.request({
                //           url: 'https://test.com/onLogin',
                //           data: {
                //             code: res.code
                //           }
                //         })
                //       } else {
                //         console.log('登录失败！' + res.errMsg)
                //       }
                //     }
                //   })

                console.log('res: ', res)

                const self = this;
                wx.getUserInfo({
                    success(res) {

                        console.log("getUserInfo: ", res);
                        self.userInfo = res.userInfo;
                        self.showScrollView();

                        // exportJson.userInfo = res.userInfo;
                        //此时可进行登录操作
                    }
                });

            } else {
                if (res.errMsg === "getUserInfo:fail auth deny") {
                    wx.showToast({
                        icon: "none",
                        title: "获取用户信息失败",
                        duration: 2000,
                    });
                } else {
                    wx.showToast({
                        icon: "none",
                        title: res.errMsg,
                        duration: 2000,
                    });
                }
            }
        });
    },
});
