// Web Audio synthesis — whistle, goal cheer, click, crowd, etc.
// No external assets. All generated on the fly.

let _ctx = null;
function getCtx() {
  if (!_ctx) {
    try { _ctx = new (window.AudioContext || window.webkitAudioContext)(); } catch (e) {}
  }
  if (_ctx && _ctx.state === 'suspended') _ctx.resume();
  return _ctx;
}

let _muted = false;
function setMuted(v) { _muted = v; }
function isMuted() { return _muted; }

function _env(gain, t, attack, decay, sustain, release, peak = 0.3) {
  gain.gain.setValueAtTime(0, t);
  gain.gain.linearRampToValueAtTime(peak, t + attack);
  gain.gain.linearRampToValueAtTime(peak * sustain, t + attack + decay);
  gain.gain.linearRampToValueAtTime(0, t + attack + decay + release);
}

function tone(freq, dur, type = 'sine', peak = 0.18, slideTo = null) {
  if (_muted) return;
  const ctx = getCtx(); if (!ctx) return;
  const o = ctx.createOscillator();
  const g = ctx.createGain();
  o.type = type;
  o.frequency.setValueAtTime(freq, ctx.currentTime);
  if (slideTo != null) o.frequency.linearRampToValueAtTime(slideTo, ctx.currentTime + dur);
  _env(g, ctx.currentTime, 0.005, 0.05, 0.6, dur - 0.05, peak);
  o.connect(g).connect(ctx.destination);
  o.start(); o.stop(ctx.currentTime + dur + 0.05);
}

function playTap() { tone(720, 0.06, 'square', 0.08); }
function playSelect() { tone(880, 0.08, 'triangle', 0.14); setTimeout(() => tone(1320, 0.10, 'triangle', 0.12), 60); }
function playWrong() { tone(220, 0.22, 'sawtooth', 0.14, 110); }
function playWhistle() {
  if (_muted) return;
  const ctx = getCtx(); if (!ctx) return;
  // double-whistle trill
  for (let i = 0; i < 2; i++) {
    setTimeout(() => {
      const o = ctx.createOscillator();
      const lfo = ctx.createOscillator();
      const lfoGain = ctx.createGain();
      const g = ctx.createGain();
      o.type = 'sine'; o.frequency.value = 2300;
      lfo.frequency.value = 28; lfoGain.gain.value = 180;
      lfo.connect(lfoGain).connect(o.frequency);
      _env(g, ctx.currentTime, 0.02, 0.05, 0.8, 0.22, 0.16);
      o.connect(g).connect(ctx.destination);
      lfo.start(); o.start();
      o.stop(ctx.currentTime + 0.32); lfo.stop(ctx.currentTime + 0.32);
    }, i * 180);
  }
}
function playGoal() {
  if (_muted) return;
  const ctx = getCtx(); if (!ctx) return;
  // Triumphant arpeggio
  const notes = [392, 523, 659, 784, 988];
  notes.forEach((f, i) => {
    setTimeout(() => tone(f, 0.18, 'triangle', 0.16), i * 70);
  });
  // crowd swell
  setTimeout(() => playCrowd(0.9), 250);
}
function playCrowd(dur = 0.6) {
  if (_muted) return;
  const ctx = getCtx(); if (!ctx) return;
  const bufferSize = Math.floor(ctx.sampleRate * dur);
  const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate);
  const data = buffer.getChannelData(0);
  for (let i = 0; i < bufferSize; i++) data[i] = (Math.random() * 2 - 1) * 0.5;
  const src = ctx.createBufferSource(); src.buffer = buffer;
  const lp = ctx.createBiquadFilter(); lp.type = 'lowpass'; lp.frequency.value = 900;
  const g = ctx.createGain();
  _env(g, ctx.currentTime, 0.08, 0.15, 0.6, dur - 0.2, 0.22);
  src.connect(lp).connect(g).connect(ctx.destination);
  src.start(); src.stop(ctx.currentTime + dur + 0.05);
}
function playTick() { tone(1400, 0.03, 'square', 0.06); }
function playReveal() {
  // ascending rapid ticks then chord
  for (let i = 0; i < 8; i++) setTimeout(() => tone(600 + i * 80, 0.04, 'square', 0.08), i * 80);
  setTimeout(() => { tone(523, 0.4, 'triangle', 0.16); tone(659, 0.4, 'triangle', 0.14); tone(784, 0.4, 'triangle', 0.12); }, 700);
}
function playCoin() { tone(1320, 0.06, 'square', 0.12); setTimeout(() => tone(1760, 0.10, 'square', 0.12), 70); }

Object.assign(window, {
  Sound: { playTap, playSelect, playWrong, playWhistle, playGoal, playCrowd, playTick, playReveal, playCoin, setMuted, isMuted, getCtx },
});
