/**
 * Pixi-адаптер оживителей: применяет выборку sampleMotion к view (position
 * относительно базовой при bob, rotation при sway, alpha/scale при
 * pulse/blink). Базы снимаются в конструкторе; позиция/поворот
 * перезаписываются только когда есть bob/sway — view с чистым blink/pulse
 * можно двигать извне. Тикается через engine.fx.
 */
import type { Container } from 'pixi.js';
import type { Updatable } from '../core/Updatables';
import { createRng } from '../math/rng';
import { sampleMotion, type MotionParams } from './motion';

export interface SpriteMotionOptions {
    /** Seed — детерминированная случайная фаза (рассинхрон кустов/искр). */
    seed?: number;
}

export class SpriteMotion implements Updatable {
    /** Живые параметры: меняйте на лету (колокол качается только при звоне). */
    params: MotionParams;

    private readonly view: Container;
    private readonly baseX: number;
    private readonly baseY: number;
    private readonly baseAlpha: number;
    private readonly baseScaleX: number;
    private readonly baseScaleY: number;
    private t = 0;

    constructor(view: Container, params: MotionParams, opts: SpriteMotionOptions = {}) {
        this.view = view;
        this.params = params;
        this.baseX = view.x;
        this.baseY = view.y;
        this.baseAlpha = view.alpha;
        this.baseScaleX = view.scale.x;
        this.baseScaleY = view.scale.y;
        if (opts.seed !== undefined) {
            // Фаза из seed: доля периода, детерминированная (без Math.random).
            const rng = createRng(opts.seed);
            const phase = (rng.int(0, 1000) / 1000);
            this.t = phase * (params.bob?.period ?? params.sway?.period ?? params.pulse?.period ?? params.blink?.period ?? 1);
        }
    }

    update(dt: number): void {
        this.t += dt;
        const s = sampleMotion(this.params, this.t);
        // Позицию/поворот трогаем только если они «живые» (bob/sway): view с
        // чистым blink/pulse имеет право двигаться извне (герой, враги).
        if (this.params.bob) {
            this.view.x = this.baseX;
            this.view.y = this.baseY + s.y;
        }
        if (this.params.sway) this.view.rotation = s.angle;
        if (this.params.blink || this.params.pulse) this.view.alpha = this.baseAlpha * s.alpha;
        if (this.params.pulse) this.view.scale.set(this.baseScaleX * s.scale, this.baseScaleY * s.scale);
    }

    /** Вернуть исходные position/rotation/alpha/scale (при выходе из сцены). */
    detach(): void {
        if (this.params.bob) {
            this.view.x = this.baseX;
            this.view.y = this.baseY;
        }
        if (this.params.sway) this.view.rotation = 0;
        if (this.params.blink || this.params.pulse) this.view.alpha = this.baseAlpha;
        if (this.params.pulse) this.view.scale.set(this.baseScaleX, this.baseScaleY);
    }

    /** Самозачистка из engine.fx: view разрушен — реестр отпустит запись. */
    get destroyed(): boolean {
        return this.view.destroyed;
    }
}