/**
 * Тряска камеры: несколько одновременных толчков, затухание линейно по времени.
 * Чистая логика (без Pixi) — смещение детерминировано seed'ом, тестируется в Vitest.
 */

import { createRng, type Rng } from '../math/rng';

interface ShakeEntry {
    strength: number;
    duration: number;
    elapsed: number;
}

export class Shake {
    private entries: ShakeEntry[] = [];
    private rng: Rng;
    private offsetX = 0;
    private offsetY = 0;

    constructor(seed = 0x5eed1234) {
        this.rng = createRng(seed);
    }

    /** Добавить толчок: амплитуда в пикселях, длительность в секундах. */
    add(strength: number, duration: number): void {
        if (strength <= 0 || duration <= 0) return;
        this.entries.push({ strength, duration, elapsed: 0 });
    }

    update(dt: number): void {
        this.offsetX = 0;
        this.offsetY = 0;
        let w = 0;
        for (const e of this.entries) {
            e.elapsed += dt;
            const k = Math.max(0, 1 - e.elapsed / e.duration); // линейное затухание
            this.offsetX += (this.rng.next() * 2 - 1) * e.strength * k;
            this.offsetY += (this.rng.next() * 2 - 1) * e.strength * k;
            if (e.elapsed < e.duration) this.entries[w++] = e; // компакт на месте, без filter
        }
        this.entries.length = w;
    }

    /** Текущее смещение в пикселях (0 вне активной тряски). */
    get offset(): { x: number; y: number } {
        return { x: Math.round(this.offsetX), y: Math.round(this.offsetY) };
    }

    get active(): boolean {
        return this.entries.length > 0;
    }

    clear(): void {
        this.entries = [];
        this.offsetX = 0;
        this.offsetY = 0;
    }
}