import Car from "../Game/Car";
import { MConst } from "../Global/MConst";
import PlayerController from "../Game/PlayerController";
import Ball from "../Global/Ball";
import Physics from "../Game/Physics";
import GameObject from "../Game/GameObject";
import { RectCollider, ColliderGroup } from "../Game/Collider";
import { MConfigs } from "../Global/MConfigs";
import PoolMgr from "../Mgr/PoolMgr";
import MTweenMgr from "../MComponents/MTween";
import Drop from "../Game/Drop";
import { MUtils } from "../Global/MUtils";
import GameMgr from "../Mgr/GameMgr";
import { arrayRemove } from "../Global/GUtils";
import MTimer from "../MComponents/MTimer";
import PhycicsSystem from "../Game/PhycicsSystem";
import Bullet from "../Game/Bullet";


export default class Game {
    /****** property ******/
    /**
     * 
     *  当前得分
     * @readonly
     */
    public get score(): number {
        return this._score;
    }

    /**
     * 当前计时器时间
     * @readonly
     */
    public get timer() {
        return this._timer;
    }

    /**
     * 子弹分数
     * @readonly
     */
    public get bulletScore(): number {
        return this._bulletScore;
    }

    /**
     * 火力分数
     * @readonly
     */
    public get powerScore(): number {
        return this._powerScore;
    }

    /**设置游戏暂停状态 */
    public set pause(v: boolean) {
        this._pause = v;

        this.timing = !this._pause; //取反
        PhycicsSystem.instance.pause = this._pause;
        MTweenMgr.instance.pause = this._pause;
    }
    public get pause() {
        return this._pause;
    }
    private _pause: boolean = false;

    /**游戏结束回调函数 */
    public onGameOver: () => void;
    /**分数改变时的回调函数 delta是分数的变化量 */
    public onScoreChange: (delta: number) => void;



    /****** public method ******/
    /**复活 */
    public revive() {
        this._car.revive();
        this.pause = false;
    }

    /**结束游戏 */
    public destroy() {
        this.scene.destroy();
        PhycicsSystem.instance.enabled = false;
    }

    constructor(parent: egret.DisplayObjectContainer) {
        PhycicsSystem.instance.enabled = true;
        this.pause = false;
        //创建墙和地面
        this.createWall();

        parent.addChild(this.scene);
        this.scene.width = MConst.DesignResolution.x;
        this.scene.height = MConst.DesignResolution.y;
        let bg = new egret.Bitmap(RES.getRes("main_bg_jpg"));
        bg.x = -10;
        bg.y = -10;
        this.scene.addChild(bg);
        //子弹层
        this._bulletLayer.touchEnabled = false;
        this.scene.addChild(this._bulletLayer);

        //炮车
        let car = new Car(this);
        car.anchorY = 1;
        car.posX = this.scene.width / 2;
        car.posY = MConst.GroundLine;
        this.scene.addChild(car);
        car.addComponent(Physics);
        car.onDied = () => {
            this.over();
        };
        this._car = car;

        //球的层
        this._ballLayer.touchEnabled = false;
        this.scene.addChild(this._ballLayer);

        //掉落物层
        this._dropLayer.touchEnabled = false;
        this.scene.addChild(this._dropLayer);

        //动画层
        this._animationLayer.touchEnabled = false;
        this.scene.addChild(this._animationLayer);

        //玩家控制器
        let playerController = new PlayerController();
        playerController.onTouchMove = (deltaX) => {
            if (!this.pause) {
                car.move(deltaX);
            }
        };
        this.scene.addChild(playerController);

        //添加监听器
        this.scene.addEventListener(egret.Event.ENTER_FRAME, this.onUpdate, this);
        this.scene.addEventListener(egret.Event.REMOVED_FROM_STAGE, () => {
            this.scene.removeEventListener(egret.Event.ENTER_FRAME, this.onUpdate, this);
        }, this);

        //开始倒计时
        this.timing = true;
    }



    /****** private method ******/

    private over() {
        this.pause = true;
        this.onGameOver && this.onGameOver();
    }

    private createWall() {
        let topWall = new GameObject();
        topWall.x = -500;
        topWall.y = -500
        this.scene.addChild(topWall);
        //添加天花板碰撞器
        let topWallCollider = topWall.addComponent<RectCollider>(RectCollider);
        topWallCollider.setData(0, 0, MConst.DesignResolution.x + 1000, 490);
        topWallCollider.group = ColliderGroup.Top;

        //创建地面节点
        let ground = new GameObject();
        ground.x = -500;
        ground.y = MConst.GroundLine;
        this.scene.addChild(ground);
        //添加地面碰撞器
        let groundCollider = ground.addComponent<RectCollider>(RectCollider);
        groundCollider.setData(0, 0, MConst.DesignResolution.x + 1000, 1000);
        groundCollider.group = ColliderGroup.Ground;

        //创建左墙节点
        let leftWall = new GameObject();
        leftWall.x = -500;
        leftWall.y = -500
        this.scene.addChild(leftWall);
        //添加左墙碰撞器
        let leftWallCollider = leftWall.addComponent<RectCollider>(RectCollider);
        leftWallCollider.setData(0, 0, 500, MConst.DesignResolution.y + 1000);
        leftWallCollider.group = ColliderGroup.Wall;

        //创建右墙节点
        let rightWall = new GameObject();
        rightWall.x = MConst.DesignResolution.x;
        rightWall.y = -500
        this.scene.addChild(rightWall);
        //添加右墙碰撞器
        let rightWallCollider = rightWall.addComponent<RectCollider>(RectCollider);
        rightWallCollider.setData(0, 0, 500, MConst.DesignResolution.y + 1000);
        rightWallCollider.group = ColliderGroup.Wall;
    }


    private createBall() {
        let size = MUtils.randomInt(0, MConfigs.size.length);
        if (GameMgr.instance.guideFlag == true) {
            size = 3;
        }
        let color = MUtils.randomInt(size, MConst.MaxColorIndex);

        let ball = this._ballPool.create(this);
        let dir: 1 | -1 = Math.random() > 0.5 ? -1 : 1;
        ball.init(dir, color, size);
        ball.startBornStage(dir);

        this.createBallCD = 1500;
    }


    private onUpdate() {
        for (let i = 0; i < this.ballList.length; i++) {
            this.ballList[i].updateScoreLabel();
        }

        //分数更新
        if (this.bulletScoreUpdateFlag) {
            let score = this._BulletScore;
            //更新最大球共存数量
            this.updateMaxBallNum(score);
            //更新开火速度
            if (score <= 20) {
                const max = MConst.BulletFireSpeed.max;
                const min = MConst.BulletFireSpeed.min;
                this._fireSpeed = min + (max - min) * (score / 20);
            } else {
                this._fireSpeed = MConst.BulletFireSpeed.max;
            }
            this._fireBulletNumConfig = Math.ceil((Math.clamp(score, 15, 140) / 2) / 10);
            this.bulletScoreUpdateFlag = false;
        }

        //检查球的创建
        if (this.createBallCD > 0) {
            this.createBallCD -= MTimer.deltaTime;
        }

        if (this.ballCount < this.curMaxBallNum) {
            if (this.createBallCD <= 0) {
                this.createBall();
            }
        }

        //倒计时
        if (this.timing) {
            if (this._timer > 0) {
                this._timer -= MTimer.deltaTime;
            } else {
                this._timer = 0;
                this.timing = false;
                //时间到
                this.pause = true;
                this.onGameOver && this.onGameOver();
            }
        }
    }

    private updateMaxBallNum(bulletScore: number) {
        let num = 0;
        if (bulletScore <= 20) num = 1;
        else if (bulletScore <= 60) num = 2;
        else if (bulletScore <= 100) num = 3
        else if (bulletScore <= 130) num = 4;
        else if (Math.random() < 0.3) num = 6;
        else num = 7;
        this.curMaxBallNum = num;
    }

    /**
     * Ball类专用
     * 不建议调用
    */
    public _shake() {
        MTweenMgr.instance.removeTweens(this.scene);

        let count = 0;
        let callback = () => {
            if (count > 1) return;
            count++;

            this.scene.x = 10;
            MTweenMgr.instance.get(this.scene)
                .wait(1, true)
                .to({ x: 0, y: -10 }, 1, true)
                .to({ x: -10, y: 0 }, 1, true)
                .to({ x: 0, y: 10 }, 1, true)
                .to({ x: 0, y: 0 }, 1, true)
                .call(callback);
        }

        callback();
    }




    /****** private field ******/

    /**不建议使用 */
    public _ballLayer: egret.DisplayObjectContainer = new egret.DisplayObjectContainer();
    /**不建议使用 */
    public _bulletLayer: egret.DisplayObjectContainer = new egret.DisplayObjectContainer(); //子弹层
    /**不建议使用 */
    public _dropLayer: egret.DisplayObjectContainer = new egret.DisplayObjectContainer();
    /**不建议使用 */
    public _animationLayer = new egret.DisplayObjectContainer();
    /**不建议使用 */
    public _fireSpeed: number = MConst.BulletFireSpeed.min;
    /**不建议使用 */
    public _fireBulletNumConfig: number = 1;
    /**不建议使用 */
    public get _score(): number {
        return this.__score;
    }
    public set _score(v: number) {
        this.onScoreChange && this.onScoreChange(v - this.__score);
        this.__score = v;
    }
    /**不建议使用 */
    public _car: Car = null;

    private __score: number = 0;
    private ballCount = 0;
    private curMaxBallNum = 1;
    private timing = false;
    private createBallCD: number = 0;
    private bulletScoreUpdateFlag = false;
    private ballList: Ball[] = [];
    private _timer: number = MConfigs.countDown * 1000;
    private scene: egret.DisplayObjectContainer = new egret.DisplayObjectContainer();

    /**不建议使用 */
    public get _BulletScore(): number {
        return this._bulletScore;
    }
    public set _BulletScore(v: number) {
        if (v == this._bulletScore) return;
        v = Math.max(v, 0);
        this._bulletScore = v;
        this.bulletScoreUpdateFlag = true;
    }
    private _bulletScore: number = 0;

    /**不建议使用 */
    public get _PowerScore(): number {
        return this._powerScore;
    }
    public set _PowerScore(v: number) {
        v = Math.max(v, 100);
        this._powerScore = v;
    }
    private _powerScore: number = 100;



    /****** inner class ******/

    /**
     *  球内存池 
     * 不建议使用
    */
    public _ballPool = new class extends PoolMgr<Ball>{
        createElement([context]: [Game]) {
            return new Ball(context);
        }

        destroy(ball: Ball) {
            super.destroy(ball);
            this.context.ballCount--;
            this.context.ballList = arrayRemove(this.context.ballList, ball);
        }

        private context: Game = null;

        constructor(context: Game) {
            super(context._ballLayer);
            this.context = context;
        }

        create(context: Game) {
            context.ballCount++;
            let ball = super.create(context);
            this.context.ballList.push(ball);
            return ball;
        }
    }(this);




    /**
     * 掉落物内存池
     * 不建议使用
     */
    public _dropPool = new class DropPool {
        private layer: egret.DisplayObjectContainer = null;
        constructor(layer: egret.DisplayObjectContainer) {
            this.layer = layer;
        }
        create(context: Game) {
            let d = new Drop(context); //暂时不对掉落物进行内存池处理
            this.layer.addChild(d);
            return d;
        }

        destroy(drop: Drop) {
            drop.destroy();
        }
    }(this._dropLayer);



    /** 
     * 子弹内存池
     * 不建议调用
    */
    public _bulletPool = new class {
        private data: Bullet[] = [];

        private layer: egret.DisplayObjectContainer = null;
        constructor(layer: egret.DisplayObjectContainer) {
            this.layer = layer;
        }

        create(context: Game) {
            if (this.data.length > 0) {
                let e = this.data.pop();
                e.onElementInit();
                return e;
            } else {
                let b = new Bullet(context);
                this.layer.addChild(b);
                return b;
            }
        }

        destroy(bullet: Bullet) {
            bullet.onElementRecycle();
            this.data.push(bullet);
        }
    }(this._bulletLayer);
}

