import { renderSpec } from '@rpg/engine';
import type { AudioManager } from '@rpg/engine';
import { SPEC_SFX, playSfx } from '../data/sfxSpecs';

/**
 * Вариативные шаги: 3 варианта на поверхность, компилируются в рантайме
 * из спеков sfxSpecs.ts (сид варианта = базовый + i·10 — звучат похоже,
 * но не идентично). Выбор варианта — по кругу. До unlock буферы не создать
 * (createBuffer → null) — играем базовый спек, варианты синтезируются
 * заново при следующих шагах, пока не получится (обычно вторая попытка,
 * после первого play).
 */

export type StepSurface = 'grass' | 'ash' | 'water' | 'floor';

const VARIANTS = 3;

export class StepVariants {
    /** Буферы по поверхности (синтезируются при первом успешном шаге). */
    private cache = new Map<StepSurface, AudioBuffer[]>();
    private seq = 0;

    constructor(private audio: AudioManager) {}

    /** Играть очередной вариант шага (до готовности буферов — базовый спек). */
    play(surface: StepSurface, volume: number): void {
        const key = `sfx/step_${surface}`;
        const list = this.ensure(surface);
        if (list.length > 0) {
            const i = this.seq++ % list.length;
            void this.audio.playBuffer(`${key}#${i}`, list[i]!, { volume });
        } else {
            playSfx(this.audio, key, { volume });
        }
    }

    /** Синтезировать варианты поверхности (если контекст ещё не готов — пустой список). */
    private ensure(surface: StepSurface): AudioBuffer[] {
        const existing = this.cache.get(surface);
        if (existing) return existing;
        const base = SPEC_SFX[`sfx/step_${surface}`];
        if (!base) return [];
        const list: AudioBuffer[] = [];
        for (let i = 0; i < VARIANTS; i++) {
            const buf = this.audio.createBuffer(renderSpec({ ...base, seed: (base.seed ?? 1) + i * 10 }), 22050);
            if (!buf) return []; // контекста нет — попробуем на следующем шаге
            list.push(buf);
        }
        this.cache.set(surface, list);
        return list;
    }
}