/**
 * Tiny WebAudio SFX engine — no assets, everything synthesized.
 */
export class Audio {
  constructor(settings) {
    this.settings = settings;
    this.ctx = null;
  }

  _ensure() {
    if (!this.settings.sound) return null;
    if (!this.ctx) {
      try {
        this.ctx = new (window.AudioContext || window.webkitAudioContext)();
      } catch { return null; }
    }
    if (this.ctx.state === 'suspended') this.ctx.resume();
    return this.ctx;
  }

  _blip(freq, dur = 0.08, type = 'square', gain = 0.04, slide = 0) {
    const ctx = this._ensure();
    if (!ctx) return;
    const o = ctx.createOscillator();
    const g = ctx.createGain();
    o.type = type;
    o.frequency.setValueAtTime(freq, ctx.currentTime);
    if (slide) o.frequency.exponentialRampToValueAtTime(Math.max(30, freq + slide), ctx.currentTime + dur);
    g.gain.setValueAtTime(gain, ctx.currentTime);
    g.gain.exponentialRampToValueAtTime(0.0001, ctx.currentTime + dur);
    o.connect(g).connect(ctx.destination);
    o.start();
    o.stop(ctx.currentTime + dur + 0.02);
  }

  place() { this._blip(620, 0.07, 'square', 0.035, -180); }
  bulldoze() { this._blip(190, 0.12, 'sawtooth', 0.03, -90); }
  zone() { this._blip(430, 0.06, 'triangle', 0.04, 140); }
  error() { this._blip(160, 0.09, 'square', 0.05); setTimeout(() => this._blip(120, 0.12, 'square', 0.05), 70); }
  cash() { this._blip(880, 0.06, 'sine', 0.04); setTimeout(() => this._blip(1320, 0.09, 'sine', 0.035), 60); }
  milestone() {
    [523, 659, 784, 1047].forEach((f, i) => setTimeout(() => this._blip(f, 0.16, 'triangle', 0.05), i * 110));
  }
  disaster() { this._blip(300, 0.4, 'sawtooth', 0.05, -220); }
  click() { this._blip(700, 0.03, 'square', 0.02); }
}
