import { TextureCache, createImage } from "../utils";
import { Tween } from "../../tween";
import { Texture, BaseTexture } from "../texture";
import { Container, Sprite, DisplayObject } from "../display";

import { getBezierEasing } from "./forLottie/BezierEaser";
import { buildBezierProps } from "./forLottie/buildBezierProps";
import { buildBezierEaserProps } from "./forLottie/buildBezierEaserProps";

interface LottieData {
    "fr": number,//珍露  30  60等
    "ip": number,//开始帧
    "op": number,//结束帧
    "w": number,//宽度
    "h": number,//高度
    "nm": string,//名字
    "layers": LayerData[],
    "assets"?: {
        "id": string,//图片id，与layers里的refId对应
        "w": number,
        "h": number,
        "p": string,//base64数据
    }[],
    "textures"?: { [key: string]: Texture }//缓存的贴图，为了上面的assets里的图片数据，不进全局缓存，

    svgaData?: any //数据生成后存入
}
interface LayerData {
    "ind": number,//id唯一
    "ty": number,//类型，暂时只有2
    "nm": string//"owl_sleep.png",//暂时就是图片
    "refId": string,
    "parent"?: number,//父级id
    "ks": KsData;
    "ip": number,//开始帧
    "op": number,//结束帧


    transformDatas?: TansformData[];
}
interface KsData {
    o: KeyData //透明度
    r: KeyData //旋转
    p: KeyData //位置
    a: KeyData //锚点
    s: KeyData //缩放
}
interface KeyData {
    a: number,
    k: KeyAniData[] | number[] | number,
    x: string,//可能有表达式

    // frames?: KeyFrameInt[],//注意根据表达式还要添加
    props?: number[][],//记录所有的属性，每一帧的
}

interface KeyAniData {
    t: number,
    s: number[],

    i: { x: number | number[], y: number | number[] },
    o: { x: number | number[], y: number | number[] },

    to: number[],
    ti: number[],

    h: number
}

/**
 * 记录的Tween数据
 */
interface TweenData {
    /**
     * 属性对象
     */
    obj: any,
    deltaTime: number,
    deltaT: number,
    isSet?: boolean,
    /**
     * 原始帧数据，算pingpong的时间差值用
     */
    timeOri?: number,
}

/**
 * 每一个属性在总帧数上每个关键点的数据
 * 挂在每个层级的的ks的各个属性上，到时直接计算出所有的x,y,sx,sy,r,alpha,  ax和ay固定，注意xy都得减axy
 * 第一步只处理ks里面的数据
 */
interface KeyFrameInt {
    /**
     * 数值
     */
    value: number[],
    /**
     * 第几帧
     */
    frame: number,

    // type: "stay" | "tween",//stay停留不变，到下一个状态时硬切  ，
    /**
     * 为了计算贝塞尔补间数据 ,有io或toti才有缓动
     */
    i?: { x: number | number[], y: number | number[] };
    o?: { x: number | number[], y: number | number[] };
    /**
     * 为了计算贝塞尔补间数据
     */
    to?: number[],
    ti?: number[],
    //不知道干嘛用的，但是有用
    h?: boolean,
}

interface TansformData {
    alpha: number;
    transform?: {
        a: number,
        b: number,
        c: number,
        d: number,
        tx: number,
        ty: number,
    };
}





/**
 * 用Tween拼，后续计算帧数据记录
 * 临时写的，真尼玛乱得很，以后再说
 */
export class Lottie extends Container {
    /**
     * 原始数据，尽量只获取，不修改
     */
    private rawData: LottieData;
    /**
     * 总帧数
     */
    get totalFrames(): number {
        return this.rawData && (this.rawData.op - this.rawData.ip) || 0;
    };
    /**
     * 锁步的时间间隔，按fps定,毫秒
     */
    private timeInterval;
    /**
     * 按帧率计算，60为1，30为2，
     */
    private deltaFrame: number = 1;

    get videoWidth(): number {
        return this.rawData && this.rawData.w || 0;
    };
    get videoHeight(): number {
        return this.rawData && this.rawData.h || 0;
    };
    /**
     * 供循环用
     */
    private loops: number
    private callback: () => void

    constructor(data) {
        super()
        this._instanceType = "Lottie";
        //初始化
        if (data) {
            this.init(data);
        }
        // else {
        //     this.totalFrames = 0;
        // }
    }
    /**
     * 暂时不考虑重复init
     * @param data 
     */
    init(data: LottieData) {
        if (!data) return
        this.rawData = data;
        this.timeInterval = 1000 / data.fr;
        // this.totalFrames = data.op - data.ip
        //间隔帧数，
        this.deltaFrame = 60 / data.fr;
        this.name = data.nm;

        //初始化图片 有assets但无textures
        if (data.assets && !data.textures) {//带图片数据的待测试
            data.textures = {};
            data.assets.forEach((a) => {
                let imgTag = createImage();
                imgTag.src = a.p;
                data.textures[a.id] = new Texture(new BaseTexture(imgTag));
            })
        }
        this.initChildren();
    }
    private initChildren() {
        //初始化内容吧，假设所有资源已经加载好额
        var layers = this.rawData.layers.slice();
        //先筛选出所有不带parents,说明是顶级容器
        for (var i = layers.length - 1; i >= 0; i--) {
            let layer = layers[i];
            // if (!layer.refId) console.log(layer)
            let c = this.addChild(new Sprite(
                // RES.getRes(layer.nm) ||
                layer.refId ?
                    this.rawData.textures ?
                        this.rawData.textures[layer.refId] :
                        TextureCache[layer.refId] ||
                        TextureCache[layer.refId + ".png"] : null
            ));
            //记录一下数据
            c["layerData"] = layer;
        }
        this.initState()
    }
    private initState(con = this.children) {
        for (var i = 0; i < con.length; i++) {
            var c = con[i] as Sprite;
            if (c["layerData"]) {
                //取第一个数据
                let data: LayerData = c["layerData"];
                //@ts-ignore 透明度
                c.alpha = data.ks.o.k[0] ? data.ks.o.k[0].s[0] / 100 : data.ks.o.k / 100;
                // c.alpha = c.alpha === 0.01 ? 1 : c.alpha;
                //@ts-ignore 选转
                c.rotation = data.ks.r.k[0] ? data.ks.r.k[0].s[0] : data.ks.r.k;
                //锚点，用贴图锚点
                var ad = typeof data.ks.a.k[0] == "number" ? data.ks.a.k : data.ks.a.k[0].s;
                c.anchor.set(ad[0], ad[1])
                //位置
                var ad = typeof data.ks.p.k[0] == "number" ? data.ks.p.k : data.ks.p.k[0].s;
                c.position.set(ad[0] - c.anchorX, ad[1] - c.anchorY)
                //缩放
                var ad = typeof data.ks.s.k[0] == "number" ? data.ks.s.k : data.ks.s.k[0].s;
                c.scale.set(ad[0] / 100, ad[1] / 100)

                //如果入场不在的
                c.visible = data.ip <= 0
                // if (data.ip > 0) {
                //     c.visible = false
                // } else {
                //     c.visible = true
                // }
            }
            if (c.children.length) this.initState(c.children)
        }
    }
    /**
     * 为了那啥 修改 loop默认0
     */
    play(loop: number = 0, callback?: () => void) {
        // this.initState();
        this.stop(true);//需要回到初始状态再开始
        this.loops = loop;
        this.callback = callback;
        this.addTweens();
    }

    /**
     * 移除所有的Tween，临时方法
     * @param isReset 是否回到初始状态，默认否
     */
    stop(isReset: boolean = false) {
        //tween要去掉
        Tween.removeTweens(this)
        this.children.forEach((c) => { Tween.removeTweens(c) })
        isReset && this.initState();
    }

    private addTweens(con = this.children) {
        for (var i = 0; i < con.length; i++) {
            let c = con[i] as Sprite;
            if (c["layerData"]) {
                //取第一个数据
                let data: LayerData = c["layerData"];
                //@ts-ignore 透明度，如果k是数组，肯定有帧数据
                if (data.ks.o.k.length) this.addTween(c, "o");
                //@ts-ignore 旋转
                if (data.ks.r.k.length) this.addTween(c, "r");
                //位置，得是对象
                if (typeof data.ks.p.k[0] != "number") this.addTween(c, "p");
                //缩放
                if (typeof data.ks.s.k[0] != "number") this.addTween(c, "s");

                //显示隐藏统一这里处理，还有个循环的，如何计算显示隐藏再说
                var t = Tween.get(c, { loop: true })
                if (data.ip > 0 || data.op < this.rawData.op) {
                    var aa = data.ip < 0 ? 0 : data.ip;
                    var bb = data.op > this.rawData.op ? this.rawData.op : data.op
                    t.wait(aa * this.timeInterval)
                        .call(() => { c.visible = true; })
                        .wait((bb - aa) * this.timeInterval)
                        .call(() => { c.visible = false; })
                        .wait((this.rawData.op - bb) * this.timeInterval)
                }

            }
            //其实不会有
            if (c.children.length) this.addTweens(c.children)
        }
        //考虑回调
        Tween.get(this, { loop: true })
            .wait((this.rawData.op - this.rawData.ip) * this.timeInterval)
            .call(() => {
                if (--this.loops == 0) {
                    this.stop();
                    this.callback && this.callback();
                }
            })
    }

    /**
     * 来吧重写，，。专干loopOut和loopIn
     * @param dis 
     * @param type 
     */
    private addTween(dis: DisplayObject, type: "r" | "o" | "s" | "p") {
        const data: { "t": number, "s": number[], "h": number }[] = dis["layerData"].ks[type].k
        let tween = Tween.get(dis, { loop: true })
        let countTime = 0;

        //有表达式的，先随便写，到时整理
        if (dis["layerData"].ks[type].x) {
            var xs = dis["layerData"].ks[type].x;
            //取数字
            var rr = +xs.replace(/[^0-9]/ig, "");
            //loopOut后续循环，补齐从最后一个数据的t到dis["layerData"].op的间隔，不足一个的情况需要单独计算
            if (xs.indexOf("loopOut") >= 0) {
                //先走完一次整的，反正补后面的
                let objArr: { obj: any, deltaTime: number, deltaT: number, isSet?: boolean }[] = [];
                let curT = 0;
                for (let i = 0; i < data.length; i++) {
                    let d = data[i];
                    //如果超过op的
                    if (d.t > dis["layerData"].op) break;
                    let deltaT = d.t - curT;
                    let deltaTime = deltaT * this.timeInterval;
                    let obj = getTweenObj(d);
                    //如果第一帧不是0，需要等待
                    if (i == 0 && d.t > 0) {
                        tween.wait(deltaTime)
                        countTime += deltaTime
                        // console.log("asdffff",countALL,d.t)
                        //需加set,但是时间0，暂时别加吧，tween会自行记录初始值
                        // objArr.push({ obj, deltaT:0, deltaTime:0, isSet: true })
                    }
                    //从0开始，但是t为0，用set
                    else if (i == 0 && d.t == 0) { //考虑下是否需要，deltaTime也是0
                        tween.set(obj);
                        objArr.push({ obj, deltaT, deltaTime, isSet: true })
                    } else {
                        //一帧当作set
                        if (d.t - curT == 1 || d.h === 1) {//1.5.0新增或者h==1
                            tween.wait(deltaTime)
                                .set(obj);
                            objArr.push({ obj, deltaT, deltaTime, isSet: true })
                            countTime += deltaTime
                            // console.log("asdff",countALL)
                        } else {
                            tween.to(obj, deltaTime);
                            objArr.push({ obj, deltaT, deltaTime })
                            countTime += deltaTime
                            // console.log("asdff",countALL)
                        }
                    }
                    //赋值
                    curT = d.t;
                }
                // if (dis["layerData"].ind == "1") console.log(45445456, objArr)
                // console.log("asdf",countALL)
                //pingpong先不考虑次数，还没遇到
                if (xs.indexOf("pingpong") >= 0 && data[data.length - 1].t < dis["layerData"].op) {
                    // Math.floor((dis["layerData"].op - data[0].t))
                    var round = Math.round(
                        (dis["layerData"].op - data[data.length - 1].t) / //其实op可能超过rawData的op所以这样有问题
                        (data[data.length - 1].t - data[0].t) //不一定所有
                    )
                    curT += round * (data[data.length - 1].t - data[0].t) //不一定所有
                    var dir = false;
                    while (--round) {//居然没判断set的，遇到问题再说TODO
                        if (dir) {
                            for (var o = 0; o < objArr.length; o++) {
                                tween.to(objArr[o].obj, objArr[o].deltaTime);
                                countTime += objArr[o].deltaTime;
                            }
                        } else {
                            for (var o = objArr.length - 1; o >= 1; o--) {
                                tween.to(objArr[o - 1].obj, objArr[o].deltaTime);
                                countTime += objArr[o].deltaTime;
                            }
                        }
                        dir = !dir;
                    }
                }
                //循环，先floor，多余的重走一次，估计不能用dis["layerData"].op，得用this.rawData.op，loopOut到时也得单独计算
                else if (xs.indexOf("cycle") >= 0 && data[data.length - 1].t < dis["layerData"].op) {
                    var lastIndex = data.length - 1;
                    var num = Math.floor(
                        (dis["layerData"].op - data[lastIndex].t) / //其实op可能超过rawData的op所以这样有问题
                        (data[lastIndex].t - data[lastIndex - (rr || lastIndex)].t)
                    );
                    // console.log("asd",num,data[lastIndex].t - data[lastIndex - (rr || lastIndex)].t)
                    //取一部分
                    let objArrC = objArr.slice(-rr);
                    while (num) {
                        num--;
                        //补满
                        for (var o = 0; o < objArrC.length; o++) {
                            if (objArrC[o].isSet) {
                                tween.wait(objArrC[o].deltaTime)
                                    .set(objArrC[o].obj);
                            } else {
                                tween.to(objArrC[o].obj, objArrC[o].deltaTime);
                            }
                            countTime += objArrC[o].deltaTime
                        }
                    }
                    // console.log("asd",countALL)
                    //补剩下的，跑一部分
                    var left = (dis["layerData"].op - data[lastIndex].t) % (data[lastIndex].t - data[lastIndex - (rr || lastIndex)].t);
                    //   if(dis["layerData"].ind=="1")  console.log(45445456,left)
                    for (var o = 0; o < objArrC.length; o++) {
                        if (objArrC[o].deltaT <= left) {
                            if (objArrC[o].isSet) {
                                tween.wait(objArrC[o].deltaTime)
                                    .set(objArrC[o].obj);
                            } else {
                                tween.to(objArrC[o].obj, objArrC[o].deltaTime);
                            }
                            left -= objArrC[o].deltaT
                            countTime += objArrC[o].deltaTime
                        } else {
                            if (left > 0) {//这种情况不会是set，再调吧，这样算补间有问题
                                // console.log(o,left, objArrC.length)
                                // if(o == 0)console.log(left, objArrC[o].deltaT)
                                var ooo = o == 0 ?
                                    calculateInterpolation(
                                        /*objArrC[0].obj,*/ copyProps(objArrC[o].obj, tween["_initQueueProps"]),//初始值用tween记录的
                                        objArrC[o].obj,
                                        left / objArrC[o].deltaT
                                    ) : calculateInterpolation(
                                        objArrC[o - 1].obj,
                                        objArrC[o].obj,
                                        left / objArrC[o].deltaT
                                    )
                                tween.to(
                                    ooo,
                                    left * this.timeInterval
                                );
                                countTime += left * this.timeInterval

                                // console.log(countALL)
                            }
                            break;
                        }
                    }

                }

            }
            //前面循环，先取所有的tween序列，初始状态要改
            else if (xs.indexOf("loopIn") >= 0) {
                let objArr: TweenData[] = [];
                let curT = 0;
                for (let i = 0; i < data.length; i++) {
                    let d = data[i];
                    //不能去掉，有可能需要用到
                    // if (d.t > dis["layerData"].op) break;
                    let deltaT = d.t - curT;
                    let deltaTime = deltaT * this.timeInterval;
                    let obj = getTweenObj(d);
                    //一帧当作set
                    if (d.t - curT == 1 || d.h === 1) {//1.5.0新增或者h==1
                        objArr.push({ obj, deltaT, deltaTime, isSet: true, timeOri: d.t })
                    } else {
                        objArr.push({ obj, deltaT, deltaTime, timeOri: d.t })
                    }
                    //赋值
                    curT = d.t;
                }
                //pingpong再loopIn暂时没有,用到时再写,还真尼玛下个就是
                if (xs.indexOf("pingpong") >= 0 && data[0].t > 0) {
                    objArr = getLoopInPingpongTween(objArr, rr, dis["layerData"].op)
                    // if (dis["layerData"].ind == 8) console.log("asdf", objArr);
                    for (var o = 0; o < objArr.length; o++) {
                        // if (dis["layerData"].ind == 8) console.log("asdf", objArrC[o]);
                        if (objArr[o].isSet) {
                            tween.wait(objArr[o].deltaTime)
                                .set(objArr[o].obj);
                        } else {
                            tween.to(objArr[o].obj, objArr[o].deltaTime);
                        }
                        countTime += objArr[o].deltaTime
                    }
                }
                //循环，其实应该用dis["layerData"].ip判断
                else if (xs.indexOf("cycle") >= 0 && data[0].t > 0) {//不考虑不整的，直接从0开始，算出整的，然后自然过度到最后一个
                    //可能入场的时间不能算
                    // if (dis["layerData"].ip > 0) tween.wait(dis["layerData"].ip * this.timeInterval)

                    objArr = getLoopInCycleTween(objArr, rr, dis["layerData"].op, dis["layerData"].ip);
                    if (dis["layerData"].ip) {
                        // console.log(5464,dis["layerData"].ip,countTime)
                        tween.wait(dis["layerData"].ip * this.timeInterval)//以后改
                        countTime += dis["layerData"].ip * this.timeInterval
                    }
                    for (var o = 0; o < objArr.length; o++) {
                        if (objArr[o].isSet) {
                            tween.wait(objArr[o].deltaTime)
                                .set(objArr[o].obj);
                        } else {
                            tween.to(objArr[o].obj, objArr[o].deltaTime);
                        }
                        countTime += objArr[o].deltaTime
                    }
                }
                // if (dis["layerData"].ind == 1) console.log("asd", countTime);
                //多余的时间
                var op = Math.min(dis["layerData"].op, this.rawData.op)
                if (countTime < op * this.timeInterval) {
                    var dd = op * this.timeInterval - countTime;
                    tween.wait(dd)
                    countTime += dd
                }
                // console.log(countTime)
                // if (dis["layerData"].ind == 1) console.log("asde", countTime);
            }

            //还有一部分   dis["layerData"].op 到 this.rawData.op 
            if (dis["layerData"].op < this.rawData.op) {
                tween.wait((this.rawData.op - dis["layerData"].op) * this.timeInterval)
                countTime += (this.rawData.op - dis["layerData"].op) * this.timeInterval
            }
            //查看所有时间
            // console.log(countTime)
        }
        //没表达式的，用wait补满前面的和后面的
        else {
            let curT = 0;
            for (let i = 0; i < data.length; i++) {
                let d = data[i],
                    obj = getTweenObj(d),
                    deltaTime;
                //判断是否小于0,小于0需要和下一帧算补间

                if (d.t < 0) {
                    //下一帧不存在或也小于0
                    if (!data[i + 1] || data[i + 1].t < 0) break;
                    obj = calculateInterpolation(
                        obj,
                        getTweenObj(data[i + 1]),
                        -d.t / (data[i + 1].t - d.t)
                    );
                    // if (d.t == -35) console.log(123)
                    tween.set(obj);
                    curT = 0;
                }
                //如果超过op的，和上一帧算补间
                else if (d.t > this.rawData.op) {
                    if (!data[i - 1] || data[i - 1].t > this.rawData.op) break;
                    let dt = this.rawData.op - data[i - 1].t;
                    deltaTime = dt * this.timeInterval;
                    obj = calculateInterpolation(
                        getTweenObj(data[i - 1]),
                        obj,
                        dt / (d.t - data[i - 1].t)
                    );
                    // if (dis["layerData"].ind == 7) console.log(999, d.t, data[i - 1].t, getTweenObj(data[i - 1]), obj)
                    tween.to(obj, deltaTime);
                    //累计时间
                    countTime += deltaTime;
                    //没必要记了。最后一帧了
                    curT = this.rawData.op;
                }
                else {
                    deltaTime = (d.t - curT) * this.timeInterval
                    //如果第一帧不是0，需要等待
                    if (i == 0 && d.t > 0) {
                        tween.wait(deltaTime)
                    }
                    //从0开始，但是t为0，用set
                    else if (i == 0 && d.t == 0) {
                        tween.set(obj);
                    } else {
                        tween.to(obj, deltaTime);
                    }
                    countTime += deltaTime
                    //赋值
                    curT = d.t;
                }
            }
            //考虑还有部分时间，等待
            if (this.rawData.op > curT) {
                tween.wait((this.rawData.op - curT) * this.timeInterval)
            }
        }
        // console.log(countTime)
        //结束的操作
        // tween.call(() => {
        //     if (--this.loops == 0) {
        //         this.stop();
        //         this.callback && this.callback();
        //     }
        // })

        /**
         * type和dis主参数里取
         * @param d 循环里取
         */
        function getTweenObj(d: { "t": number; "s": number[] }) {
            let obj;
            switch (type) {
                case "r":
                    obj = { rotation: d.s[0] }
                    break;
                case "o":
                    obj = { alpha: d.s[0] / 100 }
                    break;
                case "s":
                    obj = { scaleX: d.s[0] / 100, scaleY: d.s[1] / 100 }
                    break;
                case "p":
                    obj = { x: d.s[0] - dis.anchorX, y: d.s[1] - dis.anchorY }
                    break;
            }
            return obj;
        }
    }

    /**
     * 对所有的进行刷新，，根据cParent进行迭代刷新
     * 层级有问题，只能平铺，手动计算矩阵
     * 因为要平铺，所以记录cParent和ind  从1开始，也许只需要+1就行，还是用ind记录查找吧
     * 遍历找
     */
    updateTransform() {
        //super不行，到时查
        this.displayObjectUpdateTransform();
        this.children.forEach((c) => {
            this._recursivePostUpdateTransformAA(c);
        })
        this.children.forEach((c) => {
            c["mark"] = false;
        })
    }

    private findChildByInd(ind: number) {
        for (var i = 0; i < this.children.length; i++) {
            if (this.children[i]["layerData"] &&
                this.children[i]["layerData"].ind === ind
            ) return this.children[i]
        }
        return null
    }

    private _recursivePostUpdateTransformAA(c) {
        if (c.layerData && c.layerData.parent) {
            //ind从1开始，所以不用考虑0，且不应该存在 p没有的情况
            var p = this.findChildByInd(c.layerData.parent)
            this._recursivePostUpdateTransformAA(p);
            if (!c.mark) {
                c.mark = true;
                c.transform.updateWorldMatrix(p.transform);
                //透明度单独计算，不跟cParent保持
                c._worldAlpha = c.alpha * c.parent._worldAlpha;
            }
        }
        //直接进行tans
        else if (!c.mark) {
            c.updateTransform();//alpha跟父级有关
            c.mark = true
        }
    }

    /**
     * 加个方法，前两个参数都没用，为了一头牛
     * @param beginFrame 
     * @param endFrame 
     * @param loops 
     * @param callback 
     */
    public startAniRange(
        beginFrame: number = 1,
        endFrame: number = this.totalFrames,
        loops: number = 1,
        callback?: () => void
    ) {
        this.play(loops, callback)
    }

    destroy() {
        //tween要去掉
        Tween.removeTweens(this);
        this.children.forEach((c) => { Tween.removeTweens(c) })
        super.destroy();
    }
}


function calculateInterpolation(
    d1: any,
    d2: any,
    scale: number //时间比例 t/(t2-t1)
) {
    let obj = {};
    // for (let key in d1) obj[key] = Math.abs(d1[key] - d2[key]) * scale + d1[key]
    //之前为何要加绝对值
    for (let key in d1) obj[key] = (d2[key] - d1[key]) * scale + d1[key]
    return obj
}

/**
 * 返回一个带obj里所有的key的对象，但是key值为sObj里的
 * @param obj 取里面的key
 * @param sObj 取里面的key值
 */
function copyProps(obj, sObj) {
    var o = {};
    if (!obj) return o;
    for (let key in obj) o[key] = sObj[key];
    return o;
}

/**
 * 以后可能还会改，以后整理吧，以后可能要计算补间，现在先不管
 * @param objArr 
 * @param time 第一帧的时间间隔
 * @param round 循环索引 
 */
function getLoopInCycleTween(objArr: TweenData[], round: number, op: number, ip: number = 0) {
    var time = objArr[0].deltaT - ip;//以后算插值时再说
    //这样是否合理，也可能是objArrC的length下标，超出一个
    if (round >= objArr.length) round = 0;
    var objArrC = objArr.slice(0, round ? round + 1 : objArr.length)

    // var lastDeltaT = objArrC[objArrC.length - 1].deltaT;
    // if (objArrC.length > 2) {//如果长度大于2，首帧和尾帧是一致的，默认，所以不取最后一帧
    //     //去掉最后一帧
    //     objArrC.pop();
    // }
    // console.log(objArrC.length, objArr.length)
    var tweenArr: TweenData[] = [];
    var curIndex = 0;

    while (time > 0) {
        curIndex--;
        //超出就是最后一帧
        if (curIndex < 0) curIndex = objArrC.length - 1;

        //第0帧是set
        if (!curIndex) {
            tweenArr.unshift({
                obj: objArrC[0].obj,
                deltaT: 0,
                deltaTime: 0,
                timeOri: objArrC[0].timeOri,
                isSet: true
            })
        }
        //其他的都是终点
        else {
            tweenArr.unshift(objArrC[curIndex])
            time -= objArrC[curIndex].deltaT
        }

    }
    //第一帧加上
    tweenArr.unshift({
        obj: objArrC[0].obj,
        deltaT: 0,
        deltaTime: 0,
        timeOri: objArrC[0].timeOri,
        isSet: true
    })
    //把剩下的，第一项要变成set，再加后面的所有
    tweenArr.push({
        obj: objArrC[0].obj,
        deltaT: 0,
        deltaTime: 0,
        isSet: true
    })
    for (var i = 1; i < objArr.length; i++) {
        if (objArr[i].timeOri > op) break;
        tweenArr.push(objArr[i]);
    }
    // console.log(tweenArr)
    return tweenArr
}


function getLoopInCycleTween11(objArr: TweenData[], time: number, round: number) {
    //这样是否合理，也可能是objArrC的length下标，超出一个
    if (round >= objArr.length) round = 0;
    var lastDeltaT = objArr[round || objArr.length - 1].deltaT;
    var lastDeltaTime = objArr[round || objArr.length - 1].deltaTime;
    objArr[0].deltaT = lastDeltaT;
    objArr[0].deltaTime = lastDeltaTime;
    var objArrC = objArr.slice(0, round || objArr.length)
    var tweenArr: TweenData[] = [];
    var curT = 0;
    //从0开始，一般就是初始未知，不做任何处理，不考虑插值
    for (var i = 1; i < objArrC.length; i++) {
        tweenArr.push(objArrC[i]);//不做拷贝应该也没事
        curT += objArrC[i].deltaT;
    }
    time -= curT;
    while (time > lastDeltaT) {
        for (var i = 0; i < objArrC.length; i++) {
            tweenArr.push(objArrC[i]);//不做拷贝应该也没事
            time -= objArrC[i].deltaT
        }
    }
    //接上最后一组
    tweenArr = tweenArr.concat(objArr)
    return tweenArr
}

/**
 * pingpong的，取首尾相接的循环
 * @param objArr 
 * @param time 
 * @param round 
 */
function getLoopInPingpongTween(objArr: TweenData[], round: number, op: number) {
    var time = objArr[0].deltaT;

    if (round >= objArr.length) round = 0;
    var objArrC = objArr.slice(0, round ? round + 1 : objArr.length)

    var timeInterval = objArr[0].deltaTime / objArr[0].deltaT;
    // var allTime = 0;
    // objArrC.forEach((o, i) => { if (i != 0) allTime += o.deltaT })

    var tweenArr: TweenData[] = [];
    var dir: boolean = true// = (time / allTime) % 2 == 0;
    var curIndex = 0;
    var lastIndex = 0;
    while (time > 0) {
        dir ? curIndex++ : curIndex--;
        //如果超了，就反向
        if (curIndex > objArrC.length - 1) {
            dir = false;
            curIndex -= 2
        }
        else if (curIndex < 0) {
            dir = true;
            curIndex += 2
        }
        var deltaT = Math.abs(objArrC[lastIndex].timeOri - objArrC[curIndex].timeOri);
        tweenArr.unshift({
            obj: objArrC[lastIndex].obj,
            deltaT,
            deltaTime: deltaT * timeInterval,
            timeOri: objArrC[lastIndex].timeOri,
            isSet: objArrC[lastIndex].isSet
        })
        lastIndex = curIndex;
        time -= deltaT
    }
    //塞入
    tweenArr.unshift({
        obj: objArrC[lastIndex].obj,
        deltaT: 0,
        deltaTime: 0,
        timeOri: objArrC[lastIndex].timeOri,
        isSet: true
    })
    //把剩下的，除了第一项不要
    //得考虑超出的op
    for (var i = 1; i < objArr.length; i++) {
        if (objArr[i].timeOri > op) break;
        tweenArr.push(objArr[i]);
    }
    // objArr.forEach((o, i) => {
    //     if (i) tweenArr.push(o)
    // })



    return tweenArr
}


//动画总ip必须为0，否则修改

let totalOp: number = 0;
let lottieData: LottieData
export function lottieToSvgaData(data: LottieData) {
    //已经计算过了就直接返回了
    if (data.svgaData) return data.svgaData;
    //存一下，全局用
    totalOp = data.op;//最后一帧估计不算
    lottieData = data;
    //是否需要深拷贝
    // data = JSON.parse(JSON.stringify(data))
    //最终返回的数据 
    var videoEntity: any = {};
    //一些简单的先设置了
    videoEntity.videoSize = {
        width: data.w,
        height: data.h
    }
    videoEntity.FPS = data.fr;
    videoEntity.frames = data.op - data.ip;
    //图片还在的时
    if (data.assets) {//注意这时不能把素材干进全局。单独存在自己的数据中
        videoEntity.images = {};
        data.assets.forEach((a) => {
            videoEntity.images[a.id] = a.p.replace("data:image/png;base64,", "")//去掉相同的前缀
        })
    }
    for (var i = 0; i < data.layers.length; i++) {
        var layerData = data.layers[i];
        var ks = layerData.ks;
        //锚点是不变的，先写
        var ad: [number, number] = typeof layerData.ks.a.k[0] == "number" ? layerData.ks.a.k : layerData.ks.a.k[0].s;
        // ks.a.frames = [{ value: ad, frame: 0 }];
        //@ts-ignore
        ks.a.props = fillUp(ad);
        //其他的
        addFrames(layerData);
    }
    //开始计算每帧矩阵，注意父级，循环每帧，必须上面的先执行完毕
    data.layers.forEach((l) => {
        l.transformDatas = fillUp({
            alpha: 0,
            // transform: {
            //     a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0
            // }
        });
    })

    for (var i = 0; i < totalOp; i++) {
        data.layers.forEach((l) => {
            var ks = l.ks;
            var ip = l.ip;
            var op = l.op;
            if (i >= ip && i <= op) {
                // if()
                // console.log(ks.o.props[i], l.nm, ks.o.props.length, i)
                l.transformDatas[i].alpha = ks.o.props[i][0];
            }
            recursiveUpdateTransform(l, i);
        })
    }
    //sprites最重要的东西,里面有imageKey和frames,TODO
    videoEntity.sprites = [];
    for (var i = 0; i < data.layers.length; i++) {
        var layerData = data.layers[i];
        if (layerData.refId)//有图片的才存下，因为全部已经转换成世界矩阵。容器已经没有意义
            videoEntity.sprites.push({
                imageKey: layerData.refId,
                frames: layerData.transformDatas
            })
    }
    videoEntity.sprites.reverse()
    return lottieData.svgaData = videoEntity
}

function addFrames(layerData: LayerData) {
    var ks = layerData.ks;
    var ip = layerData.ip;
    var op = layerData.op;
    //@ts-ignore透明度
    if (ks.o.k.length) {
        addFrame(layerData, "o");
    } else {//没有直接取首诊数据，且根据ip op处理显隐 具体怎么处理好点
        //@ts-ignore 透明度决定显隐，最后根据ip和op来重新修正alpha 注意ip有可能小于0，op可能大于totalOp，所以注意判断   TODO
        var alpha = ks.o.k / 100;
        // ks.o.frames = [{ value: alpha, frame: 0 }]
        //@ts-ignore
        ks.o.props = fillUp([alpha]);
    }

    //@ts-ignore 旋转
    if (ks.r.k.length) {
        addFrame(layerData, "r");
    } else {
        //@ts-ignore
        // ks.r.frames = [{ value: ks.r.k, frame: 0 }]
        //@ts-ignore
        ks.r.props = fillUp([ks.r.k]);
    }


    //位置，得是对象
    if (typeof ks.p.k[0] != "number") {
        addFrame(layerData, "p");
    } else {
        var anchor: [number, number] = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s;
        //@ts-ignore
        var p = ks.p.k;
        // ks.p.frames = [{ value: [p[0] - anchor[0], p[1] - anchor[1]], frame: 0 }]
        //@ts-ignore
        ks.p.props = fillUp([p[0] - anchor[0], p[1] - anchor[1]]);
    }

    //缩放
    if (typeof ks.s.k[0] != "number") {
        addFrame(layerData, "s");
    } else {
        //@ts-ignore
        var s = ks.s.k;
        // ks.s.frames = [{ value: [s[0] / 100, s[1] / 100], frame: 0 }]
        //@ts-ignore
        ks.s.props = fillUp([s[0] / 100, s[1] / 100]);
    }
}

function addFrame(layerData: LayerData, type: "o" | "r" | "p" | "s") {
    //@ts-ignore
    var data: KeyAniData[] = layerData.ks[type].k;
    var ip = layerData.ip; //有小于0的情况
    var op = layerData.op; //有大于totalOp的情况
    var ks = layerData.ks;
    var anchor: [number, number] = typeof ks.a.k[0] == "number" ? ks.a.k : ks.a.k[0].s;
    var frames: KeyFrameInt[] = [];
    var props: number[][] = ks[type].props = [];
    props.length = totalOp + 1;
    for (let i = 0; i < data.length; i++) {
        let d = data[i];
        let value: number[];
        switch (type) {
            case "r":
                value = [d.s[0]];
                break;
            case "o":
                value = [d.s[0] / 100];
                break;
            case "s":
                value = [d.s[0] / 100, d.s[1] / 100, 0]
                break;
            case "p":
                value = [d.s[0] - anchor[0], d.s[1] - anchor[1], 0]
                break;
        }
        frames.push({
            i: d.i, o: d.o, ti: d.ti, to: d.to,
            h: d.h === 1,
            value,
            frame: d.t
        })
    }

    //把已有的干一边
    for (var i = 0; i < frames.length - 1; i++) {//最后一个数据不用
        let f = frames[i], nextF = frames[i + 1];
        if (f.to) {
            //把函数也传进去吧，用来处理
            var fnc = getBezierEasing(f.o.x, f.o.y, f.i.x, f.i.y).get;
            buildBezierProps(
                f.value,
                nextF.value,
                f.to,//.map((e, index) => e - anchor[index] || 0),
                f.ti,//.map((e, index) => e - anchor[index] || 0),
                f.frame,
                nextF.frame,
                props,
                fnc,
                ks[type].x ? undefined : totalOp  //没有表达式时直接加限制
            );
        }
        //没有路径，只有缓动
        else {
            buildBezierEaserProps(
                f.value,
                nextF.value,
                f.o,
                f.i,
                f.frame,
                nextF.frame,
                props,
                f.h,
                ks[type].x ? undefined : totalOp,
            )
        }
    }
    //如果是h==1的，把最后的数据加上
    if (frames[frames.length - 1].h) {
        props[frames[frames.length - 1].frame] = frames[frames.length - 1].value.slice();
    }


    //有表达式的，把最后一帧数据加上，循环有用
    if (ks[type].x && (ks[type].x.indexOf("loopOut") >= 0 || ks[type].x.indexOf("loopIn") >= 0)) {
        var xs = ks[type].x;
        var loopOut = xs.indexOf("loopOut") >= 0;
        var loopIn = xs.indexOf("loopIn") >= 0;
        //取数字
        var rr = +xs.replace(/[^0-9]/ig, "");
        if (rr > frames.length - 1) rr = 0;
        var propsClone = props.slice();
        var isCycle = xs.indexOf("cycle") >= 0;
        var isPingpong = xs.indexOf("pingpong") >= 0;

        var dir = false;
        var lastIndex = frames.length - 1;
        var startIndex = 0;
        var count = loopOut ? frames[lastIndex].frame ://开始接的那一帧
            frames[0].frame;//往前的从0开始
        var stepOffset = loopOut ? frames[lastIndex - (rr || lastIndex)].frame :
            // frames[0 + (rr || lastIndex)].frame;//循环帧数起点索引，往后补和往前补的
            frames[0].frame
        // frames[lastIndex - (rr || lastIndex)].frame
        var stepAll = loopOut ? frames[lastIndex].frame - stepOffset :
            // stepOffset - frames[0].frame; //总循环数每次，拐点只算一次,多一帧应该也计算了
            // frames[lastIndex].frame - stepOffset
            frames[0 + (rr || lastIndex)].frame - stepOffset;

        while (loopOut ?
            (/*count <= op &&*/ count <= totalOp) ://op也可能大于totalOp;
            (/*count >= ip &&*/ count >= 0)//ip他妈有可能是负的
        ) {//到op为止，其他的不算
            if (isPingpong) {
                if (dir) {//正向，第一帧不算
                    funLoop((index) => {
                        if (loopOut) {
                            props[++count] = propsClone[index + 1 + stepOffset].slice();
                        } else {
                            props[--count] = propsClone[stepAll - 1 - index + stepOffset].slice();
                        }
                    }, stepAll)
                } else {//反向，从最后一帧(不算)开始往前加剩下的
                    funLoop((index) => {
                        if (loopOut) {
                            props[++count] = propsClone[stepAll - 1 - index + stepOffset].slice();
                        } else {//从起始点参考其实是正向
                            // props[--count] = propsClone[index + 1 + stepOffset].slice();
                            props[--count] = propsClone[index + 1 + stepOffset].slice();
                        }
                    }, stepAll)
                }
                dir = !dir;
            } else if (isCycle) {
                funLoop((index) => {
                    if (loopOut) {
                        props[++count] = propsClone[index + 1 + stepOffset].slice()
                    } else {
                        props[--count] = propsClone[stepAll - 1 - index + stepOffset].slice();
                    }
                }, stepAll)
            } else {//其他情况暂时不管
                break;
            }
        }

    }
    var arr = returnEmpty(props);
    if (arr[0] !== null) {//前面补齐
        var countFront = arr[0]
        var startValue = props[countFront];
        while (countFront--) {
            props[countFront] = startValue.slice();
        }
    }
    // console.log(layerData.nm, arr)
    if (arr[1] !== null) {
        // console.log(layerData.nm, arr, arr[1])
        var countAfter = arr[1];
        var endValue = props[countAfter];
        while (countAfter++ <= totalOp) {
            props[countAfter] = endValue.slice();
        }
    }
}
function findLayerByInd(ind: number): LayerData {
    for (var i = 0; i < lottieData.layers.length; i++) {
        if (lottieData.layers[i].ind === ind) return lottieData.layers[i]
    }
    //貌似layer是按顺序的，TMD有些中间的ind是没有的，还是找吧
    // return lottieData.layers[ind - 1];
}

function recursiveUpdateTransform(l: LayerData, index: number) {
    if (l.parent !== undefined) {
        //ind从1开始，所以不用考虑0，且不应该存在 p没有的情况
        var p = findLayerByInd(l.parent)
        recursiveUpdateTransform(p, index);
        if (!l.transformDatas[index].transform) {
            //计算自己的先
            var lt = l.transformDatas[index];
            lt.transform = createWorldMatrix(
                createLocalMatrix(l, index),
                p.transformDatas[index].transform
            );
        }
    }
    //直接进行tans
    else if (!l.transformDatas[index].transform) {
        //计算顶级的自己的世界矩阵
        var lt = l.transformDatas[index];
        lt.transform = createLocalMatrix(l, index);
    }
}
//不用Matrix类，担心属性太多，直接用函数
function createLocalMatrix(l: LayerData, index: number) {
    var ks = l.ks;
    var x = 0, y = 0, scaleX = 1, scaleY = 1, rotation = 0;
    var anchorX = ks.a.props[0][0], anchorY = ks.a.props[0][1];
    if (ks.p.props[index]) {
        x = ks.p.props[index][0];
        y = ks.p.props[index][1];
    }
    if (ks.s.props[index]) {
        scaleX = ks.s.props[index][0];
        scaleY = ks.s.props[index][1];
    }
    if (ks.r.props[index]) {
        rotation = ks.r.props[index][0];
    }
    var lt: any = {};
    rotation *= Math.PI / 180;
    lt.a = Math.cos(rotation) * scaleX;
    lt.b = Math.sin(rotation) * scaleX;
    lt.c = -Math.sin(rotation) * scaleY;
    lt.d = Math.cos(rotation) * scaleY;
    lt.tx = x + anchorX - ((anchorX * lt.a) + (anchorY * lt.c));
    lt.ty = y + anchorY - ((anchorX * lt.b) + (anchorY * lt.d));
    return lt;
}

//不用Matrix类，担心属性太多，直接用函数
function createWorldMatrix(lt, pt) {
    return {
        a: (lt.a * pt.a) + (lt.b * pt.c),
        b: (lt.a * pt.b) + (lt.b * pt.d),
        c: (lt.c * pt.a) + (lt.d * pt.c),
        d: (lt.c * pt.b) + (lt.d * pt.d),
        tx: (lt.tx * pt.a) + (lt.ty * pt.c) + pt.tx,
        ty: (lt.tx * pt.b) + (lt.ty * pt.d) + pt.ty,
    }
}

function returnEmpty(arr: any[]): [number, number] {
    var front = null, after = null;
    var last = !!arr[0];
    for (var i = 1; i < arr.length; i++) {
        if (!last) {
            if (arr[i] !== undefined) {
                front = i;
            }
        } else {
            if (arr[i] === undefined) {
                after = i - 1;
                break
            }
        }
        last = !!arr[i]
    }
    return [front, after]
}

function funLoop(fun: (index: number) => void, times: number) {
    if (times <= 0) return;
    let count = times;
    // while (count--) fun(count);//刚好索引从times-1开始，到0结束
    while (count--) fun(times - count - 1);//刚好索引从0开始，到times-1结束
}

function fillUp<T>(value: T): T[] {//最后一个数据应该用不到吧
    return Array(...Array(totalOp)).map((a, i) => JSON.parse(JSON.stringify(value)));
}