import { AnimationClip } from "../AnimationClip";
import { Container } from "../display";
import { sign } from "../utils";

/**
 * 抽象动画类，暂时用于SvgaAni和Lottie的基类
 */
export abstract class AnimationNode extends Container {
    /**
     * 原始数据，尽量只获取，不修改
     */
    protected rawData: any;
    /**
     * 总时间，秒计
     */
    abstract get totalTime(): number;
    /**
     * 总帧数
     */
    abstract get totalFrames(): number;
    /**
     * 动画显示宽度
     */
    abstract get videoWidth(): number;
    /**
     * 动画显示高度
     */
    abstract get videoHeight(): number;
    /**
     * 帧率
     */
    protected _fps: number;
    /**
     * 每秒刷新帧数，没设置过直接用数据里的
     */
    abstract get fps(): number;
    /**
     * 设置每秒刷新率，可能值30，60等等
     * 子类重写get方法时必须重写set方法，否则执行不到父类的set方法
     */
    abstract set fps(value: number);
    /**
     * 重写Container父类
     * 获取videoWidth的宽度和缩放乘积
     * @member {number}
     */
    get width(): number {
        return Math.abs(this.scale.x) * this.videoWidth;
    }
    /**
     * 重写父级
     * 根据videoWidth设置自身缩放x到设置的数值
     */
    set width(value: number) {
        const s = sign(this.scale.x) || 1;
        this.scale.x = s * value / this.videoWidth;
        this._width = value;
    }

    /**
     * 获取videoHeight的高度和缩放乘积
     * @member {number}
     */
    get height(): number {
        return Math.abs(this.scale.y) * this.videoHeight;
    }
    /**
     * 根据videoHeight设置自身缩放y到设置的数值
     */
    set height(value: number) {
        const s = sign(this.scale.y) || 1;
        this.scale.y = s * value / this.videoHeight;
        this._height = value;
    }
    /**
     * 数据更新时触发，对原先设置过宽高的需要额外处理，一般在init里面自动就行
     */
    protected _onRawDataUpdate() {
        if (this._width) {
            this.width = this._width
            // this.scale.x = sign(this.scale.x) * this._width / this.videoWidth;
        }
        if (this._height) {
            this.height = this._height
            // this.scale.y = sign(this.scale.y) * this._height / this.videoHeight;
        }
    }
    /**
     * 用于控制动画，
     * Lottie和SvgaAni里面的按帧数计，animationClip.totalTime是总帧数，因为文件标记的是帧，而不是时间
     */
    protected animationClip: AnimationClip;
    constructor(data: any) {
        super();
        this._instanceType = "AnimationNode";
        this.init(data)
    }
    /**
     * 抽象的初始化类
     * @param data 
     */
    abstract init(data: any): void;

    private lastTime: number;
    /**
     * 更新方法，直接写了，后续继承的Lottie和SvgaAni基本不用改，有需要自行重写
     */
    update() {
        if (this.animationClip) {
            var now = Date.now()
            var delta = this.lastTime ? (now - this.lastTime) * 0.001 : 0.01667
            this.lastTime = now;
            //时间需要转换下帧小数，animationClip及各个track里的都是帧数
            this.animationClip.update(delta * this.fps);
        }
        super.update();
    }
    /**
     * 播放loop次后回调
     * @param loop 播放次数
     * @param callback 播放次数完后回调
     */
    play(loop?: number, callback?: () => void): void;
    /**
     * 开始播放
     * @param isFront 是否正向，默认是
     */
    play(isFront?: boolean): void;
    /**
     * 从头播放，需要自定义的用this.animationClip
     * @param {number|boolean} loop 播放测试，默认0，一直循环播放
     * @param callback 回调
     */
    play(loop?: any, callback?: () => void): void {
        if (!this.animationClip) return;
        //如果没有参数，或者第一个参数是布尔的走animationClip.play
        if (!arguments.length || typeof arguments[0] == "boolean") {
            this.animationClip.play(arguments[0]);
            return;
        }
        //其他走播放次数
        loop = loop || 0;
        this.animationClip.startAniRange(0, this.animationClip.totalTime, loop, callback)
    }
    /**
     * 停止，需要自定义的用this.animationClip
     * @param isReset 是否重置，默认false，不重置
     */
    stop(isReset: boolean = false) {
        if (!this.animationClip) return;
        isReset ? this.animationClip.gotoAndStop(0, true) : this.animationClip.stop();
    }
    /**
     * 当前帧，从0开始
     * @property currentFrame
     * @public
     * @since 1.0.0
     * @type {number}
     * @default 1
     * @readonly
     */
    get currentFrame(): number {
        return this.animationClip ? Math.round(this.animationClip.currentTime) : 0;
    }
    /**
     * 当前动画是否处于播放状态
     * @property isPlaying
     * @readOnly
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default true
     * @readonly
     */
    get isPlaying() {
        return this.animationClip ? this.animationClip.isPlaying : false
    }
    /**
     * 动画的播放方向,是顺着播还是在倒着播
     * @property isFront
     * @public
     * @since 1.0.0
     * @type {boolean}
     * @default true
     * @readonly
     */
    get isFront(): boolean {
        return this.animationClip ? this.animationClip.isFront : true;
    }
    /**
     * 停在指定时间
     * @param time 
     * @param force 是否强制更新，默认false，如果发现没stop在指定位置，可以试试设置true
     */
    gotoAndStop: (time: number, force?: boolean) => void;
    /**
     * 从某时刻开始播放
     * @param time 
     * @param isFront 默认true，正向播放
     */
    gotoAndPlay: (time: number, isFront?: boolean) => void;
    /**
     * 在一个区间范围内播放
     * @param beginTime 开始时间，秒计，默认0，
     * @param endTime 结束时间，秒计，默认_totalTime
     * @param loops 循环次数，默认1，0表示无限循环
     * @param callback 参数loop表示还剩几次
     */
    startAniRange: (beginTime: number, endTime: number, loops: number, callback?: (loop: number) => void) => void;
};
//这三个直接用clip的
["gotoAndStop", "gotoAndPlay", "startAniRange"].forEach((v) => {
    Object.defineProperty(AnimationNode.prototype, v, {
        value: function () {
            if (!this.animationClip) return;
            //直接用
            this.animationClip[v](...Array.prototype.slice.call(arguments));
        },
        writable: true,
        enumerable: true,
    })
})