/* eslint-disable @typescript-eslint/naming-convention */
/* eslint-disable import/no-mutable-exports */
/* eslint-disable max-classes-per-file */
import { Transform2D, ColorTuning, ChromaMattingConfig, VolumeRampList, Color, ScaleMode } from './types/types';

declare let console: {
  _log(...args: unknown[]);
  log(...args: unknown[]);
  error(...args: unknown[]);
};

export namespace tav {
  export const Asyncify: {
    currData: number | null
  };
  export const PLATFORM: 'browser' | 'wx' | 'nodejs' | 'engine';
  export function returnKeyframeVectorData();

  export class Int8Vector extends Vector<number> {

  }

  export interface TAVPoint {
    x: number;
    y: number;
  }

  export class TAVPoints extends Vector<TAVPoint> { }

  export class TAVMatrix {
    static MakeAll(
      scaleX: number,
      skewX: number,
      transX: number,
      skewY: number,
      scaleY: number,
      transY: number,
      persp0: number,
      persp1: number,
      persp2: number
    );
    constructor();/**
    * Sets Matrix to scale by (sx, sy). Returned matrix is:
    *
    *       | sx  0  0 |
    *       |  0 sy  0 |
    *       |  0  0  1 |
    *
    *  @param sx  horizontal scale factor
    *  @param sy  vertical scale factor
    *  @return    Matrix with scale
    */
    static MakeScale(sx: number, sy: number): TAVMatrix {
      const matrix = tav.TAVMatrix.MakeScale(sx, sy);
      const wrapper = new TAVMatrix(matrix);
      return wrapper;
    }

    /**
     * Sets Matrix to scale by (scale, scale). Returned matrix is:
     *
     *      | scale   0   0 |
     *      |   0   scale 0 |
     *      |   0     0   1 |
     *
     * @param scale  horizontal and vertical scale factor
     * @return       Matrix with scale
     */
    static MakeScale_scale(scale: number);

    /**
     * Sets Matrix to translate by (dx, dy). Returned matrix is:
     *
     *       | 1 0 dx |
     *       | 0 1 dy |
     *       | 0 0  1 |
     *
     * @param dx  horizontal translation
     * @param dy  vertical translation
     * @return    Matrix with translation
     */
    static MakeTrans(dx: number, dy: number): TAVMatrix;

    /**
     * Sets Matrix to:
     *
     *      | scaleX  skewX transX |
     *      |  skewY scaleY transY |
     *      |  pers0  pers1  pers2 |
     *
     * @param scaleX  horizontal scale factor
     * @param skewX   horizontal skew factor
     * @param transX  horizontal translation
     * @param skewY   vertical skew factor
     * @param scaleY  vertical scale factor
     * @param transY  vertical translation
     * @param pers0   input x-axis perspective factor
     * @param pers1   input y-axis perspective factor
     * @param pers2   perspective scale factor
     * @return        Matrix constructed from parameters
     */
    static MakeAll(scaleX: number, skewX: number, transX: number, skewY: number, scaleY: number,
      transY: number, pers0: number, pers1: number, pers2: number): TAVMatrix;


    /**
     * Returns true if Matrix is identity.  Identity matrix is:
     *
     *       | 1 0 0 |
     *       | 0 1 0 |
     *       | 0 0 1 |
     *
     * @return  true if Matrix has no effect
     */
    isIdentity(): boolean;


    /**
     * Returns one matrix value.
     */
    get(index: number): number;

    /**
     * Returns scale factor multiplied by x-axis input, contributing to x-axis output. With
     * mapPoints(), scales Point along the x-axis.
     * @return  horizontal scale factor
     */
    getScaleX(): number;

    /**
     * Returns scale factor multiplied by y-axis input, contributing to y-axis output. With
     * mapPoints(), scales Point along the y-axis.
     * @return  vertical scale factor
     */
    getScaleY(): number;

    /**
     * Returns scale factor multiplied by x-axis input, contributing to y-axis output. With
     * mapPoints(), skews Point along the y-axis. Skewing both axes can rotate Point.
     * @return  vertical skew factor
     */
    getSkewY(): number;

    /**
     * Returns scale factor multiplied by y-axis input, contributing to x-axis output. With
     * mapPoints(), skews Point along the x-axis. Skewing both axes can rotate Point.
     * @return  horizontal scale factor
     */
    getSkewX(): number;

    /**
     * Returns translation contributing to x-axis output. With mapPoints(), moves Point along the
     * x-axis.
     * @return  horizontal translation factor
     */
    getTranslateX(): number;

    /**
     * Returns translation contributing to y-axis output. With mapPoints(), moves Point along the
     * y-axis.
     * @return  vertical translation factor
     */
    getTranslateY(): number;


    /**
     * Sets Matrix value.
     */
    set(index: number, value: number);

    /**
     * Sets horizontal scale factor.
     * @param v  horizontal scale factor to store
     */
    setScaleX(v: number);

    /**
     * Sets vertical scale factor.
     * @param v  vertical scale factor to store
     */
    setScaleY(v: number);

    /**
     * Sets vertical skew factor.
     * @param v  vertical skew factor to store
     */
    setSkewY(v: number);

    /**
     * Sets horizontal skew factor.
     * @param v  horizontal skew factor to store
     */
    setSkewX(v: number);

    /**
     * Sets horizontal translation.
     * @param v  horizontal translation to store
     */
    setTranslateX(v: number);

    /**
     * Sets vertical translation.
     * @param v  vertical translation to store
     */
    setTranslateY(v: number);

    /**
     * Sets all values from parameters. Sets matrix to:
     *
     *      | scaleX  skewX transX |
     *      |  skewY scaleY transY |
     *      | persp0 persp1 persp2 |
     *
     * @param scaleX  horizontal scale factor to store
     * @param skewX   horizontal skew factor to store
     * @param transX  horizontal translation to store
     * @param skewY   vertical skew factor to store
     * @param scaleY  vertical scale factor to store
     * @param transY  vertical translation to store
     * @param persp0  input x-axis values perspective factor to store
     * @param persp1  input y-axis values perspective factor to store
     * @param persp2  perspective scale factor to store
     */
    setAll(scaleX: number, skewX: number, transX: number, skewY: number, scaleY: number, transY: number,
      persp0: number, persp1: number, persp2: number);

    setAffine(a: number, b: number, c: number, d: number, tx: number, ty: number);

    /**
     * Copies nine scalar values contained by Matrix into buffer, in member value ascending order:
     * kMScaleX, kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, kMPersp2.
     * @param buffer  storage for nine scalar values
     */
    get9(): number[];

    /**
     * Sets Matrix to nine scalar values in buffer, in member value ascending order: kMScaleX,
     * kMSkewX, kMTransX, kMSkewY, kMScaleY, kMTransY, kMPersp0, kMPersp1, kMPersp2.
     *
     * Sets matrix to:
     *
     *     | buffer[0] buffer[1] buffer[2] |
     *     | buffer[3] buffer[4] buffer[5] |
     *     | buffer[6] buffer[7] buffer[8] |
     *
     * @param buffer  nine scalar values
     */
    set9(buffer: number[]);

    /**
     * Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
     *
     *       | 1 0 0 |
     *       | 0 1 0 |
     *       | 0 0 1 |
     *
     * Also called setIdentity(); use the one that provides better inline documentation.
     */
    reset();

    /**
     * Sets Matrix to identity; which has no effect on mapped Point. Sets Matrix to:
     *
     *       | 1 0 0 |
     *       | 0 1 0 |
     *       | 0 0 1 |
     *
     *  Also called reset(); use the one that provides better inline documentation.
     */
    setIdentity();

    /**
     * Sets Matrix to translate by (dx, dy).
     * @param dx  horizontal translation
     * @param dy  vertical translation
     */
    setTranslate(dx: number, dy: number);

    /**
     * Sets Matrix to scale by sx and sy, about a pivot point at (px, py). The pivot point is
     * unchanged when mapped with Matrix.
     * @param sx  horizontal scale factor
     * @param sy  vertical scale factor
     * @param px  pivot on x-axis
     * @param py  pivot on y-axis
     */
    setScale(sx: number, sy: number, px: number, py: number);

    /**
     * Sets Matrix to scale by sx and sy about at pivot point at (0, 0).
     * @param sx  horizontal scale factor
     * @param sy  vertical scale factor
     */
    setScale_xy(sx: number, sy: number);

    /**
     * Sets Matrix to rotate by degrees about a pivot point at (px, py). The pivot point is
     * unchanged when mapped with Matrix. Positive degrees rotates clockwise.
     *  @param degrees  angle of axes relative to upright axes
     *  @param px       pivot on x-axis
     *  @param py       pivot on y-axis
     */
    setRotate(degrees: number, px: number, py: number);

    /**
     * Sets Matrix to rotate by degrees about a pivot point at (0, 0). Positive degrees rotates
     * clockwise.
     * @param degrees  angle of axes relative to upright axes
     */
    setRotate_deg(degrees: number);

    /**
     * Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (px, py).
     * The pivot point is unchanged when mapped with Matrix.
     * Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
     * Vector length specifies scale.
     */
    setSinCos(sinV: number, cosV: number, px: number, py: number);

    /**
     * Sets Matrix to rotate by sinValue and cosValue, about a pivot point at (0, 0).
     * Vector (sinValue, cosValue) describes the angle of rotation relative to (0, 1).
     * Vector length specifies scale.
     */
    setSinCos_sc(sinV: number, cosV: number);

    /**
     * Sets Matrix to skew by kx and ky, about a pivot point at (px, py). The pivot point is
     * unchanged when mapped with Matrix.
     * @param kx  horizontal skew factor
     * @param ky  vertical skew factor
     * @param px  pivot on x-axis
     * @param py  pivot on y-axis
     */
    setSkew(kx: number, ky: number, px: number, py: number);

    /**
     * Sets Matrix to skew by kx and ky, about a pivot point at (0, 0).
     * @param kx  horizontal skew factor
     * @param ky  vertical skew factor
     */
    setSkew_xy(kx: number, ky: number);

    /**
     * Sets Matrix to Matrix a multiplied by Matrix b. Either a or b may be this.
     *
     * Given:
     *
     *          | A B C |      | J K L |
     *      a = | D E F |, b = | M N O |
     *          | G H I |      | P Q R |
     *
     * sets Matrix to:
     *
     *              | A B C |   | J K L |   | AJ+BM+CP AK+BN+CQ AL+BO+CR |
     *      a * b = | D E F | * | M N O | = | DJ+EM+FP DK+EN+FQ DL+EO+FR |
     *              | G H I |   | P Q R |   | GJ+HM+IP GK+HN+IQ GL+HO+IR |
     *
     * @param a  Matrix on left side of multiply expression
     * @param b  Matrix on right side of multiply expression
     */
    setConcat(a: TAVMatrix, b: TAVMatrix);

    /**
     * Preconcats the matrix with the specified translate. M' = M * T(dx, dy)
     */
    preTranslate(dx: number, dy: number);

    /**
     * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
     */
    preScale(sx: number, sy: number, px: number, py: number);

    /**
     * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
     */
    preScale_xy(sx: number, sy: number);

    /**
     * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
     */
    preRotate(degrees: number, px: number, py: number);

    /**
     * Preconcats the matrix with the specified rotation. M' = M * R(degrees)
     */
    preRotate_deg(degrees: number);

    /**
     * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
     */
    preSkew(kx: number, ky: number, px: number, py: number);

    /**
     * Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
     */
    preSkew_xy(kx: number, ky: number);

    /**
     * Preconcats the matrix with the specified matrix. M' = M * other
     */
    preConcat(other: TAVMatrix);

    /**
     * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
     */
    postTranslate(dx: number, dy: number);

    /**
     * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
     */
    postScale(sx: number, sy: number, px: number, py: number);

    /**
     * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
     */
    postScale_xy(sx: number, sy: number);

    /**
     * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
     */
    postRotate(degrees: number, px: number, py: number);

    /**
     * Postconcats the matrix with the specified rotation. M' = R(degrees) * M
     */
    postRotate_deg(degrees: number);

    /**
     * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
     */
    postSkew(kx: number, ky: number, px: number, py: number);

    /**
     * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
     */
    postSkew_xy(kx: number, ky: number);

    /**
     * Postconcats the matrix with the specified matrix. M' = other * M
     */
    postConcat(other: TAVMatrix);

    /**
     * If this matrix can be inverted, return true and if inverse is not null, set inverse to be the
     * inverse of this matrix. If this matrix cannot be inverted, ignore inverse and return false.
     */

    invert(inverse: TAVMatrix): boolean;

    invertible(): boolean;

    /**
     * Maps src Point array of length count to dst Point array of equal or greater length. Point are
     * mapped by multiplying each Point by Matrix. Given:
     *
     *                | A B C |        | x |
     *       Matrix = | D E F |,  pt = | y |
     *                | G H I |        | 1 |
     *
     * where
     *
     *       for (i = 0; i < count; ++i) {
     *           x = src[i].fX
     *           y = src[i].fY
     *       }
     *
     * each dst Point is computed as:
     *
     *                     |A B C| |x|                               Ax+By+C   Dx+Ey+F
     *       Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
     *                     |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
     *
     * src and dst may point to the same storage.
     *
     * @param dst    storage for mapped Point
     * @param src    Point to transform
     * @param count  number of Point to transform
     */
    mapPoints(dst: TAVPoint[], src: TAVPoint[], count: number);

    /**
     * Maps pts Point array of length count in place. Point are mapped by multiplying each Point by
     * Matrix. Given:
     *
     *                 | A B C |        | x |
     *        Matrix = | D E F |,  pt = | y |
     *                 | G H I |        | 1 |
     *
     * where
     *
     *        for (i = 0; i < count; ++i) {
     *            x = pts[i].fX
     *            y = pts[i].fY
     *        }
     *
     * each resulting pts Point is computed as:
     *
     *                      |A B C| |x|                               Ax+By+C   Dx+Ey+F
     *        Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
     *                      |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
     *
     * @param pts    storage for mapped Point
     * @param count  number of Point to transform
     */
    mapPoints_pts(pts: TAVPoint[], count: number);


    /**
     * Returns Point (x, y) multiplied by Matrix. Given:
     *
     *                | A B C |        | x |
     *       Matrix = | D E F |,  pt = | y |
     *                | G H I |        | 1 |
     *
     * result is computed as:
     *
     *                     |A B C| |x|                               Ax+By+C   Dx+Ey+F
     *       Matrix * pt = |D E F| |y| = |Ax+By+C Dx+Ey+F Gx+Hy+I| = ------- , -------
     *                     |G H I| |1|                               Gx+Hy+I   Gx+Hy+I
     *
     * @param x  x-axis value of Point to map
     * @param y  y-axis value of Point to map
     * @return   mapped Point
     */
    mapXY(x: number, y: number): TAVPoint;

    /**
     * Returns bounds of src corners mapped by Matrix.
     */
    mapRect(src: TAVRect): TAVRect;


    /**
     * Returns the minimum scaling factor of Matrix by decomposing the scaling and skewing elements.
     * Returns -1 if scale factor overflows or Matrix contains perspective.
     */
    getMinScale(): number;

    /**
     * Returns the maximum scaling factor of Matrix by decomposing the scaling and skewing elements.
     * Returns -1 if scale factor overflows or Matrix contains perspective.
     */
    getMaxScale(): number;

    /**
     * Returns true if all elements of the matrix are finite. Returns false if any
     * element is infinity, or NaN.
     */
    isFinite(): boolean;
  }

  export interface TAVVolumeEffect {
    startTime: number,
    endTime: number,
    startVolume: number,
    endVolume: number,
    interpolationType: number,
  }

  export interface TAVPAGInput {
    id: string;
  }

  /**
   * Rect holds four float coordinates describing the upper and lower bounds of a rectangle.
   */
  export class TAVRect {
    static MakeEmpty(): TAVRect;
    static MakeWH(width: number, height: number): TAVRect;
    static MakeXYWH(x: number, y: number, width: number, height: number): TAVRect;
    static MakeLTRB(left: number, top: number, right: number, bottom: number): TAVRect;
    static Intersects(a: TAVRect, b: TAVRect): boolean;
    left: number;
    top: number;
    right: number;
    bottom: number;
    isEmpty(): boolean;
    isSorted(): boolean;
    x(): number;
    y(): number;
    width(): number;
    height(): number;
    centerX(): number;
    centerY(): number;
    setBounds(pts: TAVPoints);
    setEmpty(): void;
    setLTRB(left: number, top: number, right: number, bottom: number): void;
    setXYWH(x: number, y: number, width: number, height: number): void;
    setWH(width: number, height: number): void;
    makeOffset(dx: number, dy: number): TAVRect;
    makeInset(dx: number, dy: number): TAVRect;
    makeOutset(dx: number, dy: number): TAVRect;
    offset(dx: number, dy: number): void;
    offset_point(p: TAVPoint): void;
    offsetTo(x: number, y: number): void;
    inset(dx: number, dy: number): void;
    outset(dx: number, dy: number): void;
    scale(scaleX: number, scaleY: number): void;
    intersect(l: number, t: number, r: number, b: number): boolean;
    intersect_rect(r: TAVRect): boolean;
    intersect_rect_rect(a: TAVRect, b: TAVRect): boolean;
    intersects(l: number, t: number, r: number, b: number): boolean;
    intersects_rect(r: TAVRect): boolean;
    join(l: number, t: number, r: number, b: number): void;
    join_rect(a: TAVRect, b: TAVRect): void;
    contains(x: number, y: number): boolean;
    contains_rect(r: TAVRect): boolean;
    round(): void;
    roundOut(): void;
    sort(): void;
    makeSorted(): TAVRect;
  }


  /**
   * Textures and FrameBuffers can be stored such that (0, 0) in texture space may correspond to
   * either the top-left or bottom-left content pixel.
   */
  export const enum ImageOrigin {
    /**
     * The default origin for all off-screen rendering. Use ImageOrigin::TopLeft origin for textures
     * which are from HardwareBuffers (Android), CVPixelBuffers (iOS), or normally created by backend
     * APIs. Note: ImageOrigin::TopLeft is actual bottom-left origin for OpenGL backend.
     */
    TopLeft,
    /**
     * Use this origin to flip the content on y-axis if the GPU backend has different origin to your
     * system views. It is usually used when on-screen rendering.
     */
    BottomLeft,
  }

  export const enum PAGTimeStretchMode {
    /**
    * Keep the original playing speed, and display the last frame if the content's duration is less
    * than target duration.
    */
    None = 0,
    /*
    * Change the playing speed of the content to fit target duration.
    */
    Scale = 1,
    /**
    * Keep the original playing speed, but repeat the content if the content's duration is less than
    * target duration. This is the default mode.
    */
    Repeat = 2,
    /**
    * Keep the original playing speed, but repeat the content in reversed if the content's duration
    * is less than target duration.
    */
    RepeatInverted = 3,
  };

  export abstract class Asset {
    readonly type: string;
    path?: string;
    /**
     * Web only, used for release native objects
     */
    delete?: () => void;
    hasAudio(): boolean;
    hasVideo(): boolean;
    duration(): number;
    width(): number;
    height(): number;
  }

  export class AudioAsset extends Asset {
    static MakeFromPath(path: string, duration: number);
    static MakeFromUrl(path: string, duration: number);
    constructor(path: string);
    duration(): number;
  }

  export class ImageAsset extends Asset {
    static async MakeFromPath(path: string): ImageAsset;
    constructor(path: string);
  }
  export class MovieAsset extends Asset {
    static MakeFromPath(path: string);
    static MakeFromUrl(url: string, width: number, height: number, duration: number);
    constructor(path: string);
    duration(): number;
    frameRate(): number;
    sampleAspectRatio(): number;
  }
  export class PAGAsset extends Asset {
    static MakeFromPath(path: string);
    constructor(path: string);
    duration(): number;
  }

  /**
   * A timed audiovisual resource which provides audio or video outputs.
   */
  export abstract class Clip {
    readonly type: string;
    /**
     * Web only, used for release native objects
     */
    delete?: () => void;
    private constructor();
    /**
     * Returns the start time of this clip in the composition's timeline
     */
    startTime(): number;
    /**
     * Sets the start time of this clip in the composition's timeline.
     */
    setStartTime(time: number);

    /**
     * Returns the duration of this clip in the composition's timeline.
     */
    duration(): number;
    /**
     * Sets the duration of this clip in the composition's timeline.
     */
    setDuration(time: number);
  }

  export class Media extends Clip {
    private constructor();

    /**
     * Returns the current volume of this media, which is usually in the range [0 - 1.0].
     */
    volume(): number;

    /**
     * Sets the volume of this media, which is usually in the range [0 - 1.0].
     */
    setVolume(value: number): void;
  }
  export class Audio extends Media {
    static MakeFrom(asset: AudioAsset, contentStartTime: number, contentDuration: number);
    constructor(asset: AudioAsset, contentStartTime: number, contentDuration: number);
  }

  export class Movie extends Media {
    static MakeFrom(asset: Asset, contentStart: number, contentDuration: number): Promise<Movie>;
    static MakeFrom_range(asset: Asset, ranges: TAVVideoRanges, contentOffset: number): Promise<Movie>;
    constructor(asset: Asset, contentStartTime: number, contentDuration: number);
    /**
     * Returns the alpha value of this movie.The value of this property must be in the range 0.0
     * (transparent) to 1.0 (opaque).
     */
    opacity(): number;

    /**
     * Sets the alpha value of this movie. The value of this property must be in the range 0.0
     * (transparent) to 1.0 (opaque). Values outside that range are clamped to the minimum or maximum.
     * The default value of this property is 1.0.
     */
    setOpacity(value: number);

    // /**
    //  * Returns a copy of current matrix.
    //  */
    // matrix(): TAVMatrix;

    /**
     * Sets the transformation which specifies how this movie's video contents are positioned in
     * parent Composition.
     */
    setMatrix(value: TAVMatrix): void;

    // /**
    //  * Returns a copy of current cropRect.
    //  */
    // cropRect(): Rect;

    // /**
    //  * Sets the rectangle which specifies how this movie's video contents are cropped in parent
    //  * Composition.
    //  */
    setCropRect(value: TAVRect): void;
    width(): number;
    height(): number;
  }

  export class Composition extends Movie {
    static Make(width: number, height: number, contentStart: number, contentDuration: number);
    static toJson(clip: Clip): string;
    // todo: implement me in native
    clips?: Clip[];
    constructor(width: number, height: number, contentStart: number, contentDuration: number);
    /**
     * Adds a clip to this composition.
     */
    addClip(clip: Clip): boolean;
    /**
     * Removes a clip from this composition.
     */
    removeClip(clip: Clip): boolean;

    /**
     * Removes all clips from this composition.
     */
    removeAllClips(): void;

    // /**
    //  * get all clips
    //  */
    // getAllClips(): Clip_Vector;

    /**
     * Returns the width of the Composition.
     */
    width(): number;

    /**
    * Returns the height of the Composition.
    */
    height(): number;

    /**
    * Returns a FakeClip of the Composition.
    */
    clone(): Clip;
  }

  export abstract class Vector<T> {
    push_back(value: T): void;
    get(index: number): T;
    set(index: number, item: T): void;
    size(): number;
  }

  export class TAVTextAttribute {
    text: string;
    fillColor: Color;
    fontFamily: string;
    fontSize: number;
    fontStyle: string;
    strokeColor: Color;
    backgroundColor: Color;
  }

  export abstract class PAGEditableInfo {
    get editableIndex(): number;
  }

  export class PAGTextEditableInfo extends PAGEditableInfo {
    textAttribute: TAVTextAttribute;
  }

  export class PAGTextEditableInfos extends Vector<PAGTextEditableInfo> { }

  export interface TAVTimeRange {
    start: number;
    end: number;
  }

  export class TAVTimeRanges extends Vector<TAVTimeRange> { }

  export class TAVVideoRange {
    constructor(startTime: number, endTime: number, playDuration: number);
    get startTime(): number;
    get endTime(): number;
    get playDuration(): number;
  }
  export class TAVVideoRanges extends Vector<TAVVideoRange> { }

  export class PAGImageLayerInfo {
    layerName: string;
    layerIndex: number;
    layerTimeRange: TAVTimeRange;
    displayVideoRanges: TAVVideoRanges;
    contentDuration: number;
  }
  export class PAGImageLayerInfos extends Vector<PAGImageLayerInfo> { }

  export class PAGImageEditableInfo extends PAGEditableInfo {
    layerInfo: PAGImageLayerInfos;
  }

  export class PAGImageEditableInfos extends Vector<PAGImageEditableInfo> { }


  export class PAGSticker extends Movie {
    static MakeFrom(asset: PAGAsset);
    static MakeFromAssetStartTimeDuration(
      asset: PAGAsset,
      contentStart: number,
      contentDuration: number,
      fileDuration: number
    );
    static replaceColor(clip: PAGSticker, editableIndex: number, color: Color);
    constructor(asset: PAGAsset, contentStart: number, contentDuration: number);
    numImages(): number;
    numTexts(): number;
    async replaceImage(editableIndex: number, imagePath: String, scaleMode: ScaleMode);
    replaceText(editableIndex: number, text: String);
    replaceText_attribute(editableIndex: number, attribute: TAVTextAttribute);
    getTextAttribute(editableIndex: number): TAVTextAttribute;
    setMatrix(value: TAVMatrix): void;
  }

  export abstract class Effect extends Clip {
    // todo: implement me in native
    inputs?: Clip[];
    private constructor();
    /**
     * Adds a clip as one input source.
     */
    addInput(clip: Clip);

    /**
     * Removes the specified clip from input sources.
     */
    removeInput(clip: Clip);

    /**
     * Removes all clips from input sources.
     */
    removeAllInputs();
  }

  export class PAGImageReplacement {
    /**
     * Creates a TAVPAGImageReplacement object from a path of a image file, return null if the file
     * does not exist or it's not a valid image file.
     */
    static MakeFromPath(path: string): PAGImageReplacement | null;

    static MakeFromIndex(inputIndex: number): PAGImageReplacement;

    setMatrix(value: TAVMatrix): void;
    matrix(): TAVMatrix;

    setScaleMode(value: ScaleMode): void;
    scaleMode(): ScaleMode;

    resetMatrix(): void;
  }

  export class PAGEffect extends Effect {
    static MakeFromPath(path: string);
    constructor(path: string);
    numImages(): number;
    numTexts(): number;
    width(): number;
    height(): number;
    replaceClip(editableIndex: number, clipIndex: number, scaleMode: ScaleMode);
    replaceClipMatrix(editableIndex: number, clipIndex: number, matrix: TAVMatrix);
    replaceImage(editableIndex: number, path: string, scaleMode: ScaleMode);
    replaceImageMatrix(editableIndex: number, path: string, matrix: TAVMatrix);
    replaceLayerMatrix(name: string, matrix: TAVMatrix);
    replaceImageLayerIndexes(editableIndex: number, image: PAGImageReplacement, layerIndexes: Int8Vector)
    replaceText(editableIndex: number, text: string);
    replaceText_attribute(editableIndex: number, attribute: TAVTextAttribute);
    getTextAttribute(editableIndex: number): TAVTextAttribute;
    setMatrix(value: TAVMatrix): void;
    setCropRect(value: TAVRect): void;
    timeStretchMode(): PAGTimeStretchMode;
    setTimeStretchMode(mode: PAGTimeStretchMode): void;
    fileDuration(): number;
    getEditableTextInfo(): PAGTextEditableInfos;
    getEditableTextInfo_name(name: string): PAGTextEditableInfos;
    getEditableImageInfo(): PAGImageEditableInfos;
    getEditableImageInfo_name(name: string): PAGImageEditableInfos;
  }

  export class LUTEffect extends Effect {
    static MakeFromPath(path: string, strength: number);
    constructor(path: string);
    setStrength(strength: number);
    setPath(path: string);
  }

  export class AudioVolumeEffect extends Effect {
    static MakeVolumeEffect(clip: Clip, volumeRampList: VolumeRampList, defaultVolume: number);
    static MakeFIFOEffect(clip: Clip, maxVolume: number, fadeInDuration: number, fadeOutDuration: number);
    static getCurrentVolume(clip: Clip);
    setVolumeRamp(volumeRampList: VolumeRampList);
  }
  export class TransformEffect extends Effect {
    static MakeTransformEffect(transform2D: Transform2D);
    static updateTransform(clip: Clip, transform2D: Transform2D);
    getCurrentMatrix(): TAVMatrix;
    getCurrentOpacity(): number;
  }
  export class ColorTuningEffect extends Effect {
    static MakeColorTuningEffect(colorTuning: ColorTuning);
    static updateColorTuning(clip: Clip, colorTuning: ColorTuning);
  }
  export class ChromaMattingEffect extends Effect {
    static Make(chromaMattingConfig: ChromaMattingConfig);
    static updateConfig(clip: Clip, chromaMattingConfig: ChromaMattingConfig);
  }

  export class Keyframe {
    static MakeLinear(startTime: number, endTime: number, startVolume: number, endVolume: number);
    static MakeHold(startTime: number, endTime: number, startVolume: number, endVolume: number);
    constructor(startTime: number, endTime: number, startVolume: number, endVolume: number, interpolationType: number);
  }

  export interface PAGLayer {
    duration: number;
    startTime: number;
    name: string;
  }

  const enum LayerType {
    Unknown = 0,
    Null = 1,
    Solid = 2,
    Text = 3,
    Shape = 4,
    Image = 5,
    PreCompose = 6,
  };

  export class PAGFile {
    static Load(path: string);
    /**
     * Web only, used for release native objects
     */
    delete?: () => void;
    constructor(path: string);
    /**
     * The number of video compositions.
     */
    numVideos(): number;
    /**
     * The number of replaceable images.
     */
    numImages(): number;
    /**
     * The number of replaceable texts.
     */
    numTexts(): number;
    /**
     * Returns the width of the Composition.
     */
    height(): number;
    /**
     * Returns the height of the Composition.
     */
    width(): number;
    /**
     * The duration of the layer in microseconds, indicates the length of the visible range.
     */
    duration(): number;
    /**
     * Returns the frame rate of this layer.
     */
    frameRate(): number;
    /**
     * Return an array of layers by specified editable index and layer type.
     */
    getLayersByEditableIndex(index: number, layerType: LayerType): Array<PAGLayer>;
  }

  export class TAVSurface {
    static FromCanvas(canvasId: string): TAVSurface;
    static FromFrameBuffer(
      frameBufferID: number,
      width: number,
      height: number,
      flipY: boolean,
    ): TAVSurface;
    static MakeOffscreen(width: number, height: number): TAVSurface;
    private constructor();
    width(): number;
    height(): number;
    updateSize(): void;
    clearAll(): void;
    freeCache(): void;
    readPixels(colorType: number, alphaType: number, dstRowBytes: number): Uint8Array;
    delete();
  }

  export class TAVVideoReader {
    static MakeFrom(root: Media, frameRate: number, isRecycle: boolean): TAVVideoReader;
    private constructor();
    setSurface(surface: TAVSurface);
    seekTo(targetTime: number): Promise<boolean>;
    readNextFrame(): Promise<void>;
    scaleMode(): number;
    setScaleMode(mode: number): void;
    matrix(): TAVMatrix;
    setMatrix(matrix: TAVMatrix): void;
    release(): void;
    delete();
  }
  export class TAVAudioReader {
    static async MakeFrom(
      root: Media,
      sampleRate: number,
      sampleCount: number,
      channels: number,
      isRecycle: boolean,
    ): Promise<TAVAudioReader>;
    seekTo(targetTime: number): Promise<void>;
    readNextFrame(): Promise<void>;
    delete();
  }

  export class File {
    static readText(path: string): string;
    static writeText(content: string, path: string): void;
    static unzip(zipPath: string, resultPath: string): void;
    static setRoot(path: string): string;
  }

  export class TAVLicense {
    static Auth(licensePath: string, appId: string, key: string): number;
  }

  /**
   * @internal Web Only
   */
  export let TAVImageReader: any;

  /**
   * @internal Web Only
   */
  export let TAVVideoFrameReader: any;

  /**
   * @internal Web Only
   */
  export let TAVAudioFrameReader: any;

  /**
   * @internal Web Only
   */
  export let TAVWebAudioReader: any;

  /**
   * @internal Web Only
   */
  export let TAVMovieAudioReader: any;

  /**
   * @internal Web Only
   */
  export let TAVBitmapExecutor: {
    preload(path: string): Promise<any>;
    execute(path: string): any;
    freeBuffer(path: string): void;
  };

  /**
   * @internal Web Only
   */
  export let webAssemblyQueue: undefined | {
    public async exec(fn, scope, ...args);
  };

  export interface WebGLHandler {
    readonly currentContext: { handle: number };
    framebuffers: Array<WebGLFramebuffer>;
    registerContext(gl: WebGLRenderingContext, options: { majorVersion: number }): number;
    makeContextCurrent(handle: number);
    getNewId(table: Array): number;
  }

  export const GL: WebGLHandler;
}
export const engine: TemplateEngine;
export function setTAVModule(module: unknown);
