/**
 * Аудио игры (трек 18): AudioManager движка + темы областей. Тема — процедурная
 * партитура (data/music.ts): renderMusicStereo → AudioBuffer → луп на шине
 * music с кроссфейдом при смене области (v1 LocationAudio.playTheme). Амбиент
 * (климатические лупы v1) — не входит: на лугах тишина (по фидбеку v1),
 * шаги и боевые звуки — треки 19+.
 */
import { AudioManager, renderMusicStereo } from '@rpg/engine';
import type { MusicHandle, MusicSpec } from '@rpg/engine';
import { themeOf } from './data/music';

/** Ширина кроссфейда темы (сек) — как fade v1 (2 с лупов амбиента, музыка резче). */
const THEME_FADE = 1.2;

export class GameAudio {
    readonly manager = new AudioManager((key) => key);
    /** Запущенные темы (для моста/гейта: факт запуска видно в шпионе). */
    private current: string | null = null;
    /** Хендл текущего лупа: startSlot не занимает слот музыки — стопим сами. */
    private handle: MusicHandle | null = null;
    /** Кольцевой буфер фактических запусков (мост/гейт — как в демке). */
    readonly log: { key: string; volume: number }[] = [];

    constructor() {
        // контекст и шины синхронно: буферы компилируются до первого жеста
        this.manager.prepare();
        this.manager.unlock(); // в headless контекст разрешён без жеста
        this.manager.onPlayed = (key, opts) => {
            this.log.push({ key, volume: opts.volume ?? 1 });
            if (this.log.length > 24) this.log.shift();
        };
    }

    /** Тема области: кроссфейд на шине music; нет темы — тишина (v1: нет theme). */
    async playTheme(areaId: string): Promise<void> {
        const spec: MusicSpec | null = themeOf(areaId);
        if (spec === null) {
            if (this.current !== null) {
                this.current = null;
                this.handle?.stop(THEME_FADE);
                this.handle = null;
            }
            return;
        }
        if (this.current === areaId) return; // та же область — не перезапускать
        this.current = areaId;
        const prev = this.handle;
        this.handle = null;
        const buf = this.manager.createBuffer(renderMusicStereo(spec), 22050, 2);
        if (!buf) {
            prev?.stop(THEME_FADE);
            return;
        }
        const h = await this.manager.playLoopBuffer(`theme/${areaId}`, buf, {
            bus: 'music', fade: THEME_FADE, volume: 0.55,
        });
        // за время await область могла смениться — неактуальный луп глушим сразу
        if (this.current !== areaId) {
            h?.stop(0);
            prev?.stop(THEME_FADE);
            return;
        }
        prev?.stop(THEME_FADE); // кроссфейд: прежняя тема затухает под новой
        this.handle = h;
    }

    /** Что играет (мост/гейт). */
    get theme(): string | null {
        return this.current;
    }
}