import { Application } from 'pixi.js';
import { Game } from '../../../../phaser/dist/phaser.esm.js';
import { ReadonlyVec3 } from 'gl-matrix';
import { Scene } from '../../../../phaser/dist/phaser.esm.js';
import { vec2 } from 'gl-matrix';
import { vec3 } from 'gl-matrix';

export declare class BaseShaderProgram {
    #private;
    private readonly vertexShaderSource;
    private readonly fragmentShaderSource;
    readonly glContext: WebGL2RenderingContext;
    constructor(vertexShaderSource: string, fragmentShaderSource: string, glContext: WebGL2RenderingContext);
    setMat4: (name: string, val: Float32Array) => void;
    setMat3: (name: string, value: Float32Array) => void;
    setMat2: (name: string, value: Float32Array) => void;
    setInt: (name: string, value: number) => void;
    setFloat: (name: string, val: number) => void;
    setVec2: (name: string, val: Float32List) => void;
    setVec3: (name: string, val: Float32List) => void;
    setVec4: (name: string, val: Float32List) => void;
    setIntArray: (name: string, value: Int32Array) => void;
    setFloatArray: (name: string, value: Float32Array) => void;
    setUniformsManager(manager: ShaderUniformsManager): void;
    updateUniforms(adapter: EngineAdapter): void;
    get program(): WebGLProgram | null;
    use(): void;
    disable(): void;
    cleanup(): void;
}

export declare const configureRenderingContext: ({ gl, width, height }: {
    gl: WebGL2RenderingContext;
    width: number;
    height: number;
}) => void;

export declare const createWebGLCanvas: ({ width, height, containerId, options, }: TcreateWebGLCanvasArguments) => TcreateWebGLCanvasReturnValue;

export declare abstract class EngineAdapter {
    abstract get gl(): WebGL2RenderingContext;
    abstract get cameraMatrix(): Float32Array;
    abstract get cameraWorldMatrix(): Float32Array;
    abstract get cameraViewMatrix(): Float32Array;
    abstract get cameraProjectionMatrix(): Float32Array;
    abstract get viewportSize(): TViewportSize;
    abstract executeInGLContext(callback: (gl: WebGL2RenderingContext) => void): void;
}

declare abstract class ExecutionContext<T extends ParticleSystem = ParticleSystem> {
    abstract updateParticles(effect: ParticleEffect<T>, time: number): Promise<void> | void;
}

declare class FireSystem extends ParticleSystem<FireSystemSettings> {
    readonly settings: FireSystemSettings;
    launch(pool: MainThreadParticlePool): void;
}

declare class FireSystemSettings extends ParticleSystemSettings {
    origin: vec3;
    maxParticleSize: number;
    maxParticleVelocity: number;
    color: vec3;
    constructor(origin?: vec3, maxParticleSize?: number, maxParticleVelocity?: number, color?: vec3);
}

declare class FireworkSystem extends ParticleSystem<FireworkSystemSettings> {
    readonly settings: FireworkSystemSettings;
    shellEffect(particle: TParticleData, dt: number, time: number, seed: number, pool: MainThreadParticlePool, particleIndex: number): void;
    crackleEffect(particle: TParticleData, dt: number, time: number, seed: number, color: vec3, pool: MainThreadParticlePool): void;
    explodeEffect(particle: TParticleData, dt: number, time: number, seed: number, pool: MainThreadParticlePool): void;
    flairEffect(particle: TParticleData, dt: number, time: number, seed: number, color: vec3, size: number, pool: MainThreadParticlePool, particleIndex: number): void;
    launch(pool: MainThreadParticlePool): void;
}

declare class FireworkSystemSettings extends ParticleSystemSettings {
    origin: vec3;
    minParticleSize: number;
    maxParticleSize: number;
    maxParticleSizeStep: number;
    color: vec3;
    constructor(origin?: vec3, minParticleSize?: number, maxParticleSize?: number, maxParticleSizeStep?: number, color?: vec3);
}

declare class FountainSystem extends ParticleSystem<FountainSystemSettings> {
    readonly settings: FountainSystemSettings;
    maxSize: number;
    flairEffect(particle: TParticleData, dt: number, time: number, seed: number, size: number, pool: MainThreadParticlePool, particleIdx: number): void;
    launch(pool: MainThreadParticlePool): void;
}

declare class FountainSystemSettings extends ParticleSystemSettings {
    origin: vec3;
    maxParticleSize: number;
    maxParticleVelocity: number;
    color: vec3;
    constructor(origin?: vec3, maxParticleSize?: number, maxParticleVelocity?: number, color?: vec3);
}

declare class MainThreadParticlePool extends ParticlePool {
    readonly particlesCount: number;
    current: number;
    positions: Float32Array;
    velocities: Float32Array;
    sizes: Float32Array;
    masses: Float32Array;
    decays: Float32Array;
    lives: Float32Array;
    gravities: Float32Array;
    aliveStatus: Uint8Array;
    colors: Float32Array;
    isActionTriggeredCallbacks: Map<number, (data: TParticleData, dt: number, time: number) => boolean>;
    actions: Map<number, (data: TParticleData, dt: number, time: number) => void>;
    persistentEffects: Map<number, (data: TParticleData, dt: number, time: number) => void>;
    private physics;
    constructor(particlesCount: number);
    get data(): {
        positions: Float32Array<ArrayBufferLike>;
        colors: Float32Array<ArrayBufferLike>;
        sizes: Float32Array<ArrayBufferLike>;
        velocities: Float32Array<ArrayBufferLike>;
        masses: Float32Array<ArrayBufferLike>;
        decays: Float32Array<ArrayBufferLike>;
        lives: Float32Array<ArrayBufferLike>;
        gravities: Float32Array<ArrayBufferLike>;
        aliveStatus: Uint8Array<ArrayBufferLike>;
    };
    private initPool;
    add(data: Partial<TParticleData & TParticleCallbacks> & Pick<TParticleData, 'x' | 'y' | 'z'>): number;
    getParticle(i: number): TParticleData;
    getParticleCallbacks(i: number): TParticleCallbacks;
    updateParticle(i: number, data: Partial<TParticleData & TParticleCallbacks>): void;
    update(dt: number, i: number): void;
    reset(i: number): void;
    launchEffects(dt: number, time: number, i: number): void;
    cleanup(): void;
}

export declare class MondlichAdapter implements EngineAdapter {
    private readonly engine;
    constructor(engine: MondlichEngine);
    get viewportSize(): TViewportSize;
    get cameraWorldMatrix(): Float32Array;
    get cameraViewMatrix(): Float32Array;
    get cameraProjectionMatrix(): Float32Array;
    get cameraMatrix(): Float32Array;
    get gl(): WebGL2RenderingContext;
    executeInGLContext(callback: (gl: WebGL2RenderingContext) => void): void;
}

declare class MondlichCamera {
    private _viewConfig;
    private _projectionConfig;
    private _worldMatrix;
    private _viewMatrix;
    private _projectionMatrix;
    constructor({ viewConfig, projectionConfig }: {
        viewConfig: TCameraViewConfig;
        projectionConfig: TCameraProjectionConfig;
    });
    private updateMatrices;
    setEyePosition(eye: ReadonlyVec3): void;
    setLookAt(center: ReadonlyVec3): void;
    setUpVector(up: ReadonlyVec3): void;
    moveEye(delta: ReadonlyVec3): void;
    moveLookAt(delta: ReadonlyVec3): void;
    setFovy(fovy: number): void;
    setAspect(aspect: number): void;
    setNearPlane(near: number): void;
    setFarPlane(far: number): void;
    get worldMatrix(): Float32Array;
    get viewMatrix(): Float32Array;
    get projectionMatrix(): Float32Array;
    get eyePosition(): ReadonlyVec3;
    get lookAtPoint(): ReadonlyVec3;
    get upVector(): ReadonlyVec3;
}

export declare class MondlichEngine {
    private readonly canvas;
    readonly camera: MondlichCamera;
    readonly gl: WebGL2RenderingContext;
    constructor(canvas: HTMLCanvasElement, glOptions?: WebGLContextAttributes);
    get viewportSize(): TViewportSize;
}

export declare class MondlichMath {
    /**
     * Generates a random number between minValue (inclusive) and maxValue (exclusive)
     * @param minValue The minimum value (inclusive)
     * @param maxValue The maximum value (exclusive)
     * @returns A random number in the range [minValue, maxValue)
     */
    static randomInRange(minValue: number, maxValue: number): number;
    /**
     * Rotates a 3D point around a specified axis.
     *
     * @param point - The point to rotate as vec3 [x, y, z]
     * @param axisOrigin - Origin point of the rotation axis as vec3 [x, y, z]
     * @param axisDirection - Direction vector of the rotation axis as vec3 [x, y, z] (will be normalized)
     * @param rotationAngle - Rotation angle in radians
     * @returns The rotated point as vec3 [x, y, z]
     */
    static rotatePointAroundAxis({ point, axisOrigin, axisDirection, rotationAngle, }: {
        point: vec3;
        axisOrigin: vec3;
        axisDirection: vec3;
        rotationAngle: number;
    }): vec3;
    static randomPointOnCircle(radius: number): vec2;
    static lerp(first: number, second: number, t: number): number;
    private constructor();
}

export declare class ParticleEffect<T extends ParticleSystem> {
    private _isActive;
    _activeParticlesCount: number;
    private readonly pool;
    private readonly particleSystem;
    readonly spawnFramespan: number;
    private readonly timer;
    readonly particlesCount: number;
    frameDelta: number;
    spawnCounter: number;
    constructor({ particleSystem, particlesCount, spawnFramespan, }: TConstructorArguments<T>);
    get data(): typeof ParticleEffect.pool.data;
    set data(newData: Partial<typeof ParticleEffect.pool.data>);
    update(context: ExecutionContext, externalTime?: TUpdateTime): Promise<void>;
    updateParticles(time: number): void;
    launchParticleEffects(dt: number, time: number): void;
    start(): void;
    stop(): void;
    get isActive(): boolean;
    set isActive(value: boolean);
    get activeParticlesCount(): number;
    get settings(): TSystemSettings<T>;
    cleanup(): void;
}

export declare class ParticleEffectsManager {
    private contextManager;
    private renderer;
    private _adapter;
    private effectsData;
    readonly textureManager: TextureManager;
    constructor(adapter?: EngineAdapter);
    setAdapter(adapter: EngineAdapter): void;
    get adapter(): EngineAdapter | undefined;
    addEffect(effect: ParticleEffect<never>, renderData: RenderData): void;
    deleteEffect(effect: ParticleEffect<never>): void;
    setWorkerEnabled<T extends ParticleSystem>(effect: ParticleEffect<T>, enabled: boolean): void;
    update(externalTime?: TUpdateTime): Promise<void>;
    render(): void;
    createEffect<S extends ParticleSystemSettings, T extends ParticleSystem<S>>(options: {
        system: T;
        particlesCount: number;
        spawnFramespan?: number;
        createRenderData: (effect: ParticleEffect<never>) => RenderData;
    }): ParticleEffect<T>;
    createFirework(options: {
        particlesCount: number;
        spawnFramespan?: number;
    }): ParticleEffect<FireworkSystem>;
    createFire(options: {
        particlesCount: number;
        spawnFramespan?: number;
    }): ParticleEffect<FireSystem>;
    createFountain(options: {
        particlesCount: number;
        spawnFramespan?: number;
    }): ParticleEffect<FountainSystem>;
    createSmoke(options: {
        particlesCount: number;
        spawnFramespan?: number;
    }): ParticleEffect<SmokeSystem>;
}

declare abstract class ParticlePool {
    abstract readonly particlesCount: number;
    abstract positions: Float32Array;
    abstract velocities: Float32Array;
    abstract sizes: Float32Array;
    abstract masses: Float32Array;
    abstract decays: Float32Array;
    abstract lives: Float32Array;
    abstract gravities: Float32Array;
    abstract aliveStatus: Uint8Array;
    abstract colors: Float32Array;
    abstract get data(): {
        positions: Float32Array;
        velocities: Float32Array;
        colors: Float32Array;
        sizes: Float32Array;
        masses: Float32Array;
        decays: Float32Array;
        lives: Float32Array;
        gravities: Float32Array;
        aliveStatus: Uint8Array;
    };
    abstract getParticle(i: number): TParticleData;
    abstract update(dt: number, i: number): void;
    abstract reset(i: number): void;
}

declare abstract class ParticleSystem<S extends ParticleSystemSettings = ParticleSystemSettings> {
    abstract launch(pool: ParticlePool): void;
    abstract readonly settings: S;
}

declare abstract class ParticleSystemSettings {
}

export declare class PhaserAdapter extends EngineAdapter {
    private game;
    private scene;
    constructor(game: Game, scene: Scene);
    get gl(): WebGL2RenderingContext;
    get cameraMatrix(): Float32Array;
    get cameraWorldMatrix(): Float32Array;
    get cameraViewMatrix(): Float32Array;
    get cameraProjectionMatrix(): Float32Array;
    get viewportSize(): TViewportSize;
    executeInGLContext(callback: (gl: WebGL2RenderingContext) => void): void;
}

export declare class PixiJSAdapter extends EngineAdapter {
    private app;
    readonly gl: WebGL2RenderingContext;
    constructor(app: Application, gl: WebGL2RenderingContext);
    get cameraMatrix(): Float32Array;
    get cameraWorldMatrix(): Float32Array;
    get cameraViewMatrix(): Float32Array;
    get cameraProjectionMatrix(): Float32Array;
    get viewportSize(): TViewportSize;
    executeInGLContext(callback: (gl: WebGL2RenderingContext) => void): void;
}

export declare class RenderData {
    private readonly gl;
    readonly shaderProgram: BaseShaderProgram;
    readonly elementsCount: number;
    private vertexBuffers;
    private indexBufferConfig;
    private textures;
    constructor({ gl, shaderProgram, elementsCount, }: {
        gl: WebGLRenderingContext;
        shaderProgram: BaseShaderProgram;
        elementsCount: number;
    });
    createVertexBuffer({ name, getData, attributeConfig, usage, }: TCreateVertexBufferArguments): void;
    createVertexBuffers(buffers: Array<TCreateVertexBufferArguments>): void;
    createIndexBuffer({ data, usage, }: {
        data: Uint16Array | Uint32Array;
        usage?: number;
    }): void;
    enableVertexBuffer(name: string): void;
    enableAllVertexBuffers(): void;
    enableIndexBuffer(): void;
    createTexture({ name, unit, source, width, height, }: {
        name: string;
        unit: number;
        source?: TexImageSource | null;
        width?: number;
        height?: number;
    }): void;
    bindTextures(): void;
    disableAllVertexBuffers(): void;
    disableIndexBuffer(): void;
    disableTextures(): void;
    dispose(): void;
    get hasIndexBuffer(): boolean;
    get program(): BaseShaderProgram;
}

declare abstract class ShaderUniformsManager {
    abstract updateUniforms({ adapter, shader }: {
        adapter: EngineAdapter;
        shader: BaseShaderProgram;
    }): void;
}

declare class SmokeSystem extends ParticleSystem {
    readonly settings: SmokeSystemSettings;
    launch(pool: MainThreadParticlePool): void;
}

declare class SmokeSystemSettings extends ParticleSystemSettings {
    origin: [number, number, number];
    maxParticleSize: number;
    maxParticleVelocity: number;
    color: vec3;
    constructor(origin?: [number, number, number], maxParticleSize?: number, maxParticleVelocity?: number, color?: vec3);
}

declare type TCameraProjectionConfig = {
    fovy: number;
    aspect: number;
    nearPlane: number;
    farPlane: number;
};

declare type TCameraViewConfig = {
    eye: vec3;
    center: vec3;
    up: vec3;
};

declare type TConstructorArguments<T extends ParticleSystem> = {
    particleSystem: T;
    particlesCount: number;
    spawnFramespan: number;
};

declare type TCreateVertexBufferArguments = {
    name: string;
    getData: () => Float32Array;
    attributeConfig: TVertexAttribPointerConfig;
    usage?: number;
};

declare type TcreateWebGLCanvasArguments = {
    width: number;
    height: number;
    containerId: string;
    options?: WebGLContextAttributes;
};

declare type TcreateWebGLCanvasReturnValue = {
    canvas: HTMLCanvasElement;
    gl: WebGL2RenderingContext;
};

declare class TextureManager {
    private textureCache;
    loadImage(id: string, url: string): Promise<HTMLImageElement>;
    getTexture(id: string): HTMLImageElement;
    loadTextureLibrary(): Promise<HTMLImageElement[]>;
}

export declare class Timer {
    private startTime;
    private oldTime;
    private elapsedTime;
    private running;
    constructor(autoStart?: boolean);
    start(): void;
    stop(): void;
    getElapsedTime(): number;
    getDelta(): number;
    get isRunning(): boolean;
}

declare type TParticleCallbacks = {
    isActionTriggered: (data: TParticleData, dt: number, time: number) => boolean;
    action: (data: TParticleData, dt: number, time: number) => void;
    persistentEffect: (data: TParticleData, dt: number, time: number) => void;
};

declare type TParticleData = {
    x: number;
    y: number;
    z: number;
    vx: number;
    vy: number;
    vz: number;
    mass: number;
    alive: boolean;
    size: number;
    decay: number;
    life: number;
    gravity: number;
    r: number;
    g: number;
    b: number;
};

declare type TSystemSettings<T> = T extends ParticleSystem<infer S> ? S : never;

declare type TUpdateTime = {
    time: number;
    delta: number;
};

declare type TVertexAttribPointerConfig = {
    size: number;
    type: number;
    normalized: boolean;
    stride: number;
    offset: number;
};

declare type TViewportSize = {
    width: number;
    height: number;
};

export declare class UserInput {
    private camera;
    private timer;
    private sensitivity;
    private isDragging;
    private lastX;
    private lastY;
    private worldUpVector;
    private moveSpeed;
    private rotateSpeed;
    private keys;
    constructor({ camera, sensitivity, moveSpeed, rotateSpeed, worldUpVector, }: {
        camera: MondlichCamera;
        sensitivity?: number;
        moveSpeed?: number;
        rotateSpeed?: number;
        worldUpVector?: vec3;
    });
    private setupEventListeners;
    private onMouseDown;
    private onMouseMove;
    private onMouseUp;
    update(): void;
    private handleKeyboardInput;
    private rotateCamera;
    private isEventCodeInKeys;
    private onKeyDown;
    private onKeyUp;
    dispose(): void;
}

export { }
