import DisplayCollider, { Tag } from "./DisplayCollider";
import { MConst } from "../MConst";
import { Decorator } from "../Decorator/Decorator";
import GameMgr from "../Mgr/GameMgr";
import DebugMgr from "../Mgr/DebugMgr";
import GameStage from "./GameStage";
import { MTweenObject } from "./MTween";

export default abstract class GameObject extends DisplayCollider {
    /**每帧速率的增量。x坐标表示水平方向速率的增量，为标量，单位为像素/帧；y轴同上。 */
    protected acceleration: egret.Point = new egret.Point();

    private timerList: MTimer[] = [];

    public shadow: Shadow;
    protected gameStage: GameStage

    protected _center: egret.Point = new egret.Point();
    public get center(): egret.Point {
        this._center.x = this.x + this.width / 2;
        this._center.y = this.y + this.height / 2;
        return this._center;
    }


    constructor(tag: Tag, localRect: egret.Rectangle, gameStage: GameStage) {
        super(tag, localRect);
        this.gameStage = gameStage;
        this.onDraw();

        this.addEventListener(egret.Event.ADDED_TO_STAGE, () => {
            this.shadow.visible = true;
            this.shadow.update();
        }, this);

        // egret.Ticker.getInstance().register(this.onFixedUpdate, this);
        // egret.startTick(this.onFixedUpdate, this);
    }

    /**@virtual */
    protected onDraw() {
        this.onCreateShadow();
        this.gameStage.shadowLayer.addChild(this.shadow);
    }

    protected abstract onCreateShadow(): void;

    public moveTo(x: number | egret.Point, y?: number) {
        if (typeof x == "number") {
            if (!y) {
                console.error("invalid param");
                return;
            }

            this.moveTo(new egret.Point(x, y));
        } else {
            let target: egret.Point = x;
            let bottomY = this.y + this.height;
            let curBottomcPos = new egret.Point(this.x, bottomY);
            let bottomTarget = new egret.Point(target.x, target.y + this.height);
            if (bottomTarget.y == bottomY) { //防止下面的除零异常
                this.x = target.x;
                return;
            }

            let groundLine = GameMgr.instance.groundLineInGameStage;
            let targetBottomToGroundLine = groundLine - bottomTarget.y;
            let displace = bottomTarget.subtract(curBottomcPos);
            if (displace.y >= 0 && targetBottomToGroundLine <= 0) {
                let ratio = (groundLine - bottomY) / (bottomTarget.y - bottomY);
                displace.x *= ratio;
                displace.y *= ratio;
                bottomTarget = curBottomcPos.add(displace);
                this.x = bottomTarget.x;
                this.y = bottomTarget.y - this.height;
            } else {
                this.x = target.x;
                this.y = target.y;
            }
        }
    }

    public land(x: number, y: number = 0) {
        this.x = x;
        this.y = (GameMgr.instance.groundLineInGameStage - this.height) + y;
    }

    public get position() {
        return new egret.Point(this.x, this.y);
    }

    /**速度 单位：像素/帧 */
    public get velocity() {
        return this._velocity;
    }
    public set velocity(v: egret.Point) {
        this._velocity = v;
    }
    private _velocity: egret.Point = new egret.Point();

    /**@override */
    onUpdate() {
        super.onUpdate();
        this.onFixedUpdate();
        this.shadow && this.shadow.update();
    }

    /**@virtual */
    onFixedUpdate() {
        this.velocity.x += this.acceleration.x;
        this.velocity.y += this.acceleration.y;
        if (this.velocity.length > 0) {
            this.moveTo(this.position.add(this.velocity));
        }

        return false;
    }

    /**@override */
    onDestroy() {
        super.onDestroy();
        MTweenObject.removeTweens(this);
        egret.Tween.removeTweens(this);
        this.timerList.forEach(e => e.destroy());
        this.timerList = null;
        this.shadow.destroy();
        // egret.Ticker.getInstance().unregister(this.onFixedUpdate, this);
        // egret.stopTick(this.onFixedUpdate, this);
    }

    public setTimer(time: number, onTimeOut: () => void, repeat?: number, onRepeated?: () => void): MTimer {
        let timer = new MTimer(time, onTimeOut, repeat, () => {
            onRepeated && onRepeated();
            //执行完毕，在列表中删除自身
            this.timerList.splice(this.timerList.indexOf(timer), 1);
        });
        this.timerList.push(timer);
        return timer;
    }

    public delay(time: number): Promise<void> {
        return new Promise<void>(resolve => {
            this.setTimer(time, () => {
                resolve();
            });
        });
    }
}

export class MTimer {
    private timer: egret.Timer = null;

    constructor(time: number, onTimeOut: () => void, repeat?: number, onRepeated?: () => void) {
        //创建一个计时器对象
        let timer: egret.Timer = new egret.Timer(time, repeat || 1);
        //注册事件侦听器
        timer.addEventListener(egret.TimerEvent.TIMER, onTimeOut, this);
        timer.addEventListener(egret.TimerEvent.TIMER_COMPLETE, onRepeated || (() => { }), this);
        //开始计时
        timer.start();
        this.timer = timer;
    }

    stop() {
        this.timer.stop();
    }

    destroy() {
        this.stop();
        this.timer = null;
    }
}

export class Shadow extends egret.Bitmap {
    public target: egret.DisplayObject;
    constructor(texture: egret.Texture, target?: egret.DisplayObject) {
        super(texture);
        // this.anchorOffsetX = texture.textureWidth / 2;
        this.anchorOffsetY = texture.textureHeight / 2;
        this.target = target;
        this.y = GameMgr.instance.groundLineInGameStage;
        this.visible = false;
    }

    /**@virtual */
    public update() {
        if (!this.target) return;

        this.x = this.target.x + this.target.width / 2 - this.width / 2;
        let bottomY = this.target.y + this.target.height;
        let scale = 1;
        if (bottomY >= GameMgr.instance.groundLineInGameStage)
            scale = 1;
        else if (bottomY < 0) {
            scale = 0;
        }
        else
            scale = bottomY / GameMgr.instance.groundLineInGameStage;
        this.scaleX = scale;
        this.scaleY = scale;
    }
}