declare module SVGA {
    export interface ParserPostMessageArgs {
        url: string;
        options: {
            isDisableImageBitmapShim: boolean;
        };
    }

    export interface MockWebWorker {
        onmessage: (event: {
            data: ParserPostMessageArgs;
        }) => void;
        onmessageCallback: (data: Video | Error) => void;
        postMessage: (data: Video | Error) => void;
    }

    export interface ParserConfigOptions {
        /**
         * 是否取消使用 WebWorker，默认值 false
         */
        isDisableWebWorker?: boolean;
        /**
         * 是否取消使用 ImageBitmap 垫片，默认值 false
         */
        isDisableImageBitmapShim?: boolean;
    }

    export interface RawImages {
        [key: string]: string | HTMLImageElement | ImageBitmap;
    }

    export interface Rect {
        x: number;
        y: number;
        width: number;
        height: number;
    }

    export interface Transform {
        a: number;
        b: number;
        c: number;
        d: number;
        tx: number;
        ty: number;
    }

    export const enum LINE_CAP_CODE {
        BUTT = 0,
        ROUND = 1,
        SQUARE = 2
    }

    export const enum LINE_JOIN_CODE {
        MITER = 0,
        ROUND = 1,
        BEVEL = 2
    }

    export interface RGBA_CODE {
        r: number;
        g: number;
        b: number;
        a: number;
    }

    export type RGBA<R extends number, G extends number, B extends number, A extends number> = `rgba(${R}, ${G}, ${B}, ${A})`;

    export const enum SHAPE_TYPE_CODE {
        SHAPE = 0,
        RECT = 1,
        ELLIPSE = 2,
        KEEP = 3
    }

    export const enum SHAPE_TYPE {
        SHAPE = "shape",
        RECT = "rect",
        ELLIPSE = "ellipse"
    }

    export interface MovieStyles {
        fill: RGBA_CODE | null;
        stroke: RGBA_CODE | null;
        strokeWidth: number | null;
        lineCap: LINE_CAP_CODE | null;
        lineJoin: LINE_JOIN_CODE | null;
        miterLimit: number | null;
        lineDashI: number | null;
        lineDashII: number | null;
        lineDashIII: number | null;
    }

    export interface VideoStyles {
        fill: RGBA<number, number, number, number> | null;
        stroke: RGBA<number, number, number, number> | null;
        strokeWidth: number | null;
        lineCap: CanvasLineCap | null;
        lineJoin: CanvasLineJoin | null;
        miterLimit: number | null;
        lineDash: number[] | null;
    }

    export interface ShapePath {
        d: string;
    }

    export interface RectPath {
        x: number;
        y: number;
        width: number;
        height: number;
        cornerRadius: number;
    }

    export interface EllipsePath {
        x: number;
        y: number;
        radiusX: number;
        radiusY: number;
    }

    export interface MovieShape {
        type: SHAPE_TYPE_CODE | null;
        shape: ShapePath | null;
        rect: RectPath | null;
        ellipse: EllipsePath | null;
        styles: MovieStyles | null;
        transform: Transform | null;
    }

    export interface VideoShapeShape {
        type: SHAPE_TYPE.SHAPE;
        path: ShapePath;
        styles: VideoStyles;
        transform: Transform;
    }

    export interface VideoShapeRect {
        type: SHAPE_TYPE.RECT;
        path: RectPath;
        styles: VideoStyles;
        transform: Transform;
    }

    export interface VideoShapeEllipse {
        type: SHAPE_TYPE.ELLIPSE;
        path: EllipsePath;
        styles: VideoStyles;
        transform: Transform;
    }

    export interface MaskPath {
        d: string;
        transform: Transform | undefined;
        styles: VideoStyles;
    }

    export interface MovieFrame {
        alpha: number;
        transform: Transform | null;
        nx: number;
        ny: number;
        layout: Rect;
        clipPath: string;
        maskPath: MaskPath | null;
        shapes: MovieShape[];
    }

    export type VideoFrameShape = VideoShapeShape | VideoShapeRect | VideoShapeEllipse;

    export type VideoFrameShapes = VideoFrameShape[];

    export interface VideoFrame {
        alpha: number;
        transform: Transform | null;
        nx: number;
        ny: number;
        layout: Rect;
        clipPath: string;
        maskPath: MaskPath | null;
        shapes: VideoFrameShapes;
    }

    export interface MovieSprite {
        imageKey: string;
        frames: MovieFrame[];
    }

    export interface VideoSprite {
        imageKey: string;
        frames: VideoFrame[];
    }

    export type Bitmap = HTMLImageElement | OffscreenCanvas | ImageBitmap;

    export interface BitmapsCache {
        [key: string]: Bitmap | ImageBitmap;
    }

    export type ReplaceElement = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;

    export interface ReplaceElements {
        [key: string]: ReplaceElement;
    }

    export type DynamicElement = HTMLImageElement | HTMLCanvasElement | OffscreenCanvas;

    export interface DynamicElements {
        [key: string]: DynamicElement;
    }

    export interface Movie {
        version: string;
        images: {
            [key: string]: Uint8Array;
        };
        params: {
            fps: number;
            frames: number;
            viewBoxHeight: number;
            viewBoxWidth: number;
        };
        sprites: MovieSprite[];
    }

    export interface Video {
        version: string;
        size: {
            width: number;
            height: number;
        };
        fps: number;
        frames: number;
        images: RawImages;
        replaceElements: ReplaceElements;
        dynamicElements: DynamicElements;
        sprites: VideoSprite[];
    }

    export const enum PLAYER_FILL_MODE {
        /**
         * 播放完成后停在首帧
         */
        FORWARDS = "forwards",
        /**
         * 播放完成后停在尾帧
         */
        BACKWARDS = "backwards"
    }

    export const enum PLAYER_PLAY_MODE {
        /**
         * 顺序播放
         */
        FORWARDS = "forwards",
        /**
         * 倒序播放
         */
        FALLBACKS = "fallbacks"
    }

    export interface PlayerConfig {
        /**
         * 播放动画的 Canvas 元素
         */
        container: HTMLCanvasElement;
        /**
         * 循环次数，默认值 0（无限循环）
         */
        loop: number | boolean;
        /**
         * 最后停留的目标模式，类似于 animation-fill-mode，默认值 forwards。
         */
        fillMode: PLAYER_FILL_MODE;
        /**
         * 播放模式，默认值 forwards
         */
        playMode: PLAYER_PLAY_MODE;
        /**
         * 开始播放的帧数，默认值 0
         */
        startFrame: number;
        /**
         * 结束播放的帧数，默认值 0
         */
        endFrame: number;
        /**
         * 循环播放的开始帧，默认值 0
         */
        loopStartFrame: number;
        /**
         * 是否开启缓存已播放过的帧数据，默认值 false
         */
        isCacheFrames: boolean;
        /**
         * 是否开启动画容器视窗检测，默认值 false
         * 开启后利用 Intersection Observer API 检测动画容器是否处于视窗内，若处于视窗外，停止描绘渲染帧避免造成资源消耗
         */
        isUseIntersectionObserver: boolean;
        /**
         * 是否使用避免执行延迟，默认值 false
         * 开启后使用 `WebWorker` 确保动画按时执行（避免个别情况下浏览器延迟或停止执行动画任务）
         */
        isOpenNoExecutionDelay: boolean;
    }

    export type PlayerConfigOptions = Partial<PlayerConfig>;

    export class Parser {
        worker: MockWebWorker | Worker;
        private readonly isDisableImageBitmapShim;

        constructor(options?: ParserConfigOptions);

        /**
         * 通过 url 下载并解析 SVGA 文件
         * @param url SVGA 文件的下载链接
         * @returns Promise<SVGA 数据源>
         */
        load(url: string): Promise<Video>;

        /**
         * 销毁实例
         */
        destroy(): void;
    }

    export class Animator {
        private isRunning;
        private startTime;
        private currentFrication;
        private worker;
        isOpenNoExecutionDelay: boolean;
        startValue: number;
        endValue: number;
        duration: number;
        loopStart: number;
        loop: number;
        fillRule: number;
        onStart: () => void;
        onUpdate: (currentValue: number) => void;
        onEnd: () => void;
        currentTimeMillsecond: () => number;

        start(): void;

        stop(): void;

        get animatedValue(): number;

        private doFrame;
        private doDeltaTime;
    }

    export function render(canvas: HTMLCanvasElement | OffscreenCanvas, bitmapsCache: BitmapsCache, dynamicElements: DynamicElements, replaceElements: ReplaceElements, videoEntity: Video, currentFrame: number): void;

    export class Player {
        /**
         * 动画当前帧数
         */
        currentFrame: number;
        /**
         * 动画总帧数
         */
        totalFrames: number;
        /**
         * SVGA 数据源
         */
        videoEntity: Video | undefined;
        /**
         * 当前配置项
         */
        readonly config: PlayerConfig;
        readonly animator;
        private readonly ofsCanvas;
        private isBeIntersection;
        private intersectionObserver;
        private bitmapsCache;
        private readonly cacheFrames;

        constructor(options: HTMLCanvasElement | PlayerConfigOptions);

        /**
         * 设置配置项
         * @param options 可配置项
         */
        setConfig(options: PlayerConfigOptions): void;

        private setIntersectionObserver;

        /**
         * 装载 SVGA 数据元
         * @param videoEntity SVGA 数据源
         * @returns Promise<void>
         */
        mount(videoEntity: Video): Promise<void>;

        /**
         * 开始播放事件回调
         */
        onStart: EventCallback;
        /**
         * 重新播放事件回调
         */
        onResume: EventCallback;
        /**
         * 暂停播放事件回调
         */
        onPause: EventCallback;
        /**
         * 停止播放事件回调
         */
        onStop: EventCallback;
        /**
         * 播放中事件回调
         */
        onProcess: EventCallback;
        /**
         * 播放结束事件回调
         */
        onEnd: EventCallback;
        private clearContainer;

        /**
         * 开始播放
         */
        start(): void;

        /**
         * 重新播放
         */
        resume(): void;

        /**
         * 暂停播放
         */
        pause(): void;

        /**
         * 停止播放
         */
        stop(): void;

        /**
         * 清理容器画布
         */
        clear(): void;

        /**
         * 销毁实例
         */
        destroy(): void;

        private startAnimation;
        private setSize;
        private drawFrame;
    }

    export {};

    export class DB {
        private readonly storeName;
        private readonly dbPromise;

        constructor({name, version, storeName}?: {
            name: string;
            version: number;
            storeName: string;
        });

        find(id: IDBValidKey): Promise<Video | undefined>;

        insert(id: IDBValidKey, data: Video): Promise<void>;

        delete(id: IDBValidKey): Promise<void>;
    }
}
