import MoveObjcet from "./MoveObject";
import Collider, { CircleCollider, ColliderGroup } from "../Phycics/Collider";
import { MConfigs } from "../Global/MConfigs";
import { getBallScore, getProp } from "../Global/GUtils";
import { PoolElement } from "../Component/Pool";
import { MConst } from "../Global/MConst";
import Drop from "./Drop";
import Bullet from "./Bullet";
import { MUtils } from "../Global/MUtils";
import SoundMgr from "../Mgr/SoundMgr";
import { DataMgr } from "../Mgr/DataMgr";
import GuideMgr from "../Mgr/GuideMgr";
import MTimer from "../Global/MTimer";

let tempPower: number = null;
let tempIndexOffset: number = null;
const imageNames = [
    "39843f75-8caa-4cee-bff5-91fb759b691b",
    "bd94b3e6-3c99-490f-95ef-ca0c056d7727",
    "d8eab9fc-104e-4b39-88d6-455ed8632703",
    "48f98d84-d30e-4dfe-aa92-c45bde5cefd8",
    "8d42fd9e-907b-4587-9a6f-a634909b8b8a"
];

const textureSize = {
    width: 210,
    height: 213
};

export default class Ball extends MoveObjcet implements PoolElement {
    private colorIndex = 0;
    private sizeIndex = 0;
    private bitmap: engine.Sprite = null;
    public static textures: engine.Texture[] = [];
    // private labelScore: SpriteFontLabel = null;
    // private labelScoreShadow: engine.Label = null;
    private scaleRatio: number = 1;
    private initScore: number = null;
    private initColorIndex: number = 0;
    public collider: CircleCollider = null;
    private isBornStage = false;
    public poolKey: string = null;

    private _score = 0;
    public get score() {
        return this._score;
    }
    public set score(v: number) {
        if (v < 0) v = 0;
        //分数标签更新
        if (this._score != v) {
            this.scoreUpdateFlag = true;
        }

        this._score = v;
    }

    // private static ballTextures: engine.Texture[] = [];
    /* public static loadTextures() {
        for (let i in imageNames) {
            Ball.ballTextures[i] = RES.getRes(imageNames[i]);
        }
    } */

    private onScoreIsZero() {
        if (GuideMgr.instance.guideFlag == true) {
            this.drop();
        } else {
            if (this.sizeIndex > 0) {
                this.split();
            } else {
                this.drop();
            }
        }

        DataMgr.game._playBoomEffect(this.position, this.scaleRatio);
        SoundMgr.instance.playEffect("boom");
        DataMgr.game._pool.ball.recycle(this.poolKey, this);
    }

    constructor(sizeIndex: number) {
        super();
        //获取配置
        let scaleRatio = MConfigs.size[sizeIndex]; //整体缩放系数

        //创建图像
        const bitmapWidth = textureSize.width * scaleRatio;
        const bitmapHeight = textureSize.height * scaleRatio;
        this.bitmap = new engine.Sprite();
        this.addChild(this.bitmap);
        this.bitmap.width = bitmapWidth;
        this.bitmap.height = bitmapHeight;
        this.anchorX = bitmapWidth / 2;
        this.anchorY = bitmapHeight / 2;
        this.bitmap.x = -bitmapWidth / 2;
        this.bitmap.y = -bitmapHeight / 2;

        //创建文字
        /* let labelScore = new SpriteFontLabel(new SpriteFont("num_font"), "");
        labelScore.scaleX = labelScore.scaleY = scaleRatio;
        labelScore.y = -labelScore.height / 2;
        this.addChild(labelScore); */

        //添加碰撞器
        let collider = this.addComponent(CircleCollider) as CircleCollider;
        collider.group = ColliderGroup.Ball;
        this.collider = collider;
        collider.setData(0, 0, bitmapHeight / 2);

        //初始化属性
        this.scaleRatio = scaleRatio;
        this.sizeIndex = sizeIndex;
        // this.labelScore = labelScore;
    }

    init(colorIndex: number, direction: 1 | -1, score: number): Ball {
        this.colorIndex = colorIndex;
        this.initColorIndex = colorIndex;
        this.bitmap.texture = RES.getRes(imageNames[colorIndex]);

        this.initScore = score;
        this.score = score;
        this.physics.rotateVelocity = direction * MConst.BallRotateSpeed * Math.pow(1 / this.scaleRatio, 0.5);
        return this;
    }

    startBornStage(dir: 1 | -1) {
        this.isBornStage = true;
        if (dir == 1) {
            this.x = 0 - this.width / 2 - 10;
        } else if (dir == -1) {
            this.x = MConst.DesignResolution.width + this.width / 2 + 10;
        }
        this.y = MConst.BallInitPosY;

        this.physics.velocity.x = this.getRandomVelocityX(dir) + 1 * dir;
        this.dir = dir;
        this.physics.onMoved = this.onBornStageMoved.bind(this)
    }

    private dir: 1 | -1 = 1;

    private onBornStageMoved(owner: Ball) {
        if (this.dir == 1) {
            if (this.x > this.width / 2) {
                this.startGravityStage(this.dir);
                this.physics.onMoved = null;
            }
        } else if (this.dir == -1) {
            if (this.x < MConst.DesignResolution.width - this.width / 2) {
                this.startGravityStage(this.dir);
                this.physics.onMoved = null;
            }
        }
    }

    private getRandomVelocityX(direction: 1 | -1) {
        return direction * MConst.BallVelocityX * (1 + ((1 / this.scaleRatio) - 1) * MUtils.random(0, MConst.BallVelocityXRandomFactor));
    }

    startGravityStage(direction: 1 | -1) {
        this.isBornStage = false;
        this.physics.velocity.x = this.getRandomVelocityX(direction);
        this.physics.acceleration.y = MConst.Gravity;
    }

    onCollisionEnter(other: Collider) {
        if (other.group == ColliderGroup.Bullet) {
            tempPower = (other.owner as Bullet).power;
            this.score = this.score - tempPower;
            DataMgr.game._score += tempPower;
        }

        if (other.group == ColliderGroup.Ground) {
            this.physics.velocity.y = -(MConst.BallVelocityY * (1 + ((1 / this.scaleRatio) - 1) * MUtils.random(0, MConst.BallVelocityYRandomFactor)));

            //播放灰尘动画
            const clip = DataMgr.game._createAnimation("duang");
            clip.x = this.x - 140 * this.scaleRatio;
            clip.y = this.y - 50 * this.scaleRatio;
            clip.scaleX = clip.scaleY = this.scaleRatio;
            clip.play();
            //判断是否会震动地面
            if (this.sizeIndex >= MConfigs.size.length - 2) {
                DataMgr.game._shake();
                SoundMgr.instance.playEffect("dong");
            }
        }

        if (other.group == ColliderGroup.Wall && !this.isBornStage) {
            this.physics.velocity.x = -this.physics.velocity.x;
            this.physics.rotateVelocity = -this.physics.rotateVelocity;
        }
    }

    onCollisionStay(other: Collider) {
        if (other.group == ColliderGroup.Wall && !this.isBornStage) {
            let dir: 1 | -1 = other.owner.x < 0 ? 1 : -1;
            this.physics.velocity.x = dir * Math.abs(this.physics.velocity.x);
            this.physics.rotateVelocity = dir * Math.abs(this.physics.rotateVelocity);

        }
    }

    /**@inheritdoc */
    onElementRecycle() {
        this.visible = false;
        this.physics.velocity.y = 0;
        this.physics.velocity.x = 0;
        this.physics.acceleration.y = 0;
        this.physics.acceleration.x = 0;
        this.disableAllComponents();

    }
    onElementInit() {
        this.visible = true;
        this.enableAllComponents();
    }

    private split() {
        let sizeIndex = this.sizeIndex - 1;
        let score = Math.ceil(this.initScore / 2 * (Math.random() * 0.4 + 0.8));
        let colorIndex = Math.max(this.initColorIndex - 1, 0);

        let callback = (direction: 1 | -1) => {
            let ball = DataMgr.game._pool.ball.spwan(sizeIndex).init(colorIndex, direction, score);
            ball.x = this.x;
            ball.y = this.y;
            ball.startGravityStage(direction);
            ball.physics.velocity.y = -MConst.BallSplitVelocityY;

        }

        callback(1);
        callback(-1);
    }

    private scoreUpdateFlag = false;

    public updateScoreLabel() {
        if (this.scoreUpdateFlag == true) {
            // const score = this.score;
            /* if (score >= 1000) {
                this.labelScore.text = (Math.floor(score / 100) / 10).toString() + "k";
            } else {
                this.labelScore.text = score.toString();
            }
            this.labelScore.x = -this.labelScore.width / 2; */

            this.scoreUpdateFlag = false;

            //判断是否需要更改颜色
            /* if (this.initScore == null) return;
            if (score > 0) {
                tempIndexOffset = Math.floor((this.initScore - score) / this.initScore / (1 / (this.initColorIndex + 1)));
                if (this.initColorIndex - tempIndexOffset != this.colorIndex) { //目标颜色和当前颜色不一致
                    //更新颜色
                    this.colorIndex = this.initColorIndex - tempIndexOffset;
                    this.bitmap.texture = Ball.ballTextures[this.colorIndex];
                }
            } else {
                this.onScoreIsZero();
            } */

            if (this.score <= 0) {
                this.onScoreIsZero();
            }
        }
    }

    private drop() {
        //掉落数
        let index = 1;
        //根据子弹分数判断索引
        let bulletScore = DataMgr.game.bulletScore;
        if (bulletScore <= 30) index = 0;
        else if (bulletScore > 30 && bulletScore <= 70) index = 1;
        else if (bulletScore > 70) index = 2;
        //根据索引获取配置
        let config: {
            num: number,
            factor: object
        } = MConfigs.dropPool[index];

        let keys = Object.keys(config.factor);
        let values = keys.map(e => config.factor[e]);
        let dropIds: number[] = getProp(keys, values, config.num);

        let drops: Drop[] = [];
        for (let id of dropIds) {
            drops.push(DataMgr.game._pool.drop.spwan(id.toString()));
        }

        let dir = this.x > MConst.DesignResolution.width / 2 ? -1 : 1;

        for (let i = 0; i < drops.length; i++) {
            let drop = drops[i];
            drop.x = this.x - drop.bitmap.width / 2;
            drop.y = this.y - drop.bitmap.height / 2;
            let offsetRatio = (i - 1) + (2 - (drops.length - 1));
            let x = MConst.DropVelocityX.x + offsetRatio * MConst.DropVelocityX.offset;

            x *= MUtils.random(1 - MConst.DropRandomFactor, 1 + MConst.DropRandomFactor);
            drop.physics.velocity.x = dir * x;
            drop.physics.velocity.y = -(x * 5 * MUtils.random(0.9, 1.1));

            if (GuideMgr.instance.guideFlag && i == 1) {
                MTimer.setFrameTimer(20, () => {
                    GuideMgr.instance.runGuide(1, drop.x, drop.y, true);
                });
            }
        }
    }
}