/**
 * Prozedurale Sound-Engine auf Basis der WebAudio API.
 * Keine Audio-Dateien nötig – alles wird live synthetisiert.
 */

export type SoundName = "tick" | "coin" | "dice" | "pop" | "win" | "whoosh";

let ctx: AudioContext | null = null;

function ac(): AudioContext | null {
  if (typeof window === "undefined") return null;
  try {
    if (!ctx) {
      const AC =
        window.AudioContext ||
        (window as unknown as { webkitAudioContext?: typeof AudioContext })
          .webkitAudioContext;
      if (!AC) return null;
      ctx = new AC();
    }
    if (ctx.state === "suspended") {
      ctx.resume().catch(() => {});
    }
    return ctx;
  } catch {
    return null;
  }
}

function tone(
  c: AudioContext,
  freq: number,
  type: OscillatorType,
  dur: number,
  peak = 0.2,
  when = 0,
  slideTo?: number,
) {
  const t0 = c.currentTime + when;
  const osc = c.createOscillator();
  const gain = c.createGain();
  osc.type = type;
  osc.frequency.setValueAtTime(freq, t0);
  if (slideTo) {
    osc.frequency.exponentialRampToValueAtTime(slideTo, t0 + dur);
  }
  gain.gain.setValueAtTime(0, t0);
  gain.gain.linearRampToValueAtTime(peak, t0 + 0.008);
  gain.gain.exponentialRampToValueAtTime(0.0001, t0 + dur);
  osc.connect(gain).connect(c.destination);
  osc.start(t0);
  osc.stop(t0 + dur + 0.05);
}

function noiseBurst(
  c: AudioContext,
  dur: number,
  peak: number,
  filterFreq: number,
  when = 0,
  sweepTo?: number,
) {
  const t0 = c.currentTime + when;
  const len = Math.max(1, Math.floor(c.sampleRate * dur));
  const buffer = c.createBuffer(1, len, c.sampleRate);
  const data = buffer.getChannelData(0);
  for (let i = 0; i < len; i++) data[i] = Math.random() * 2 - 1;

  const src = c.createBufferSource();
  src.buffer = buffer;
  const filter = c.createBiquadFilter();
  filter.type = "bandpass";
  filter.frequency.setValueAtTime(filterFreq, t0);
  filter.Q.value = 1.1;
  if (sweepTo) {
    filter.frequency.exponentialRampToValueAtTime(sweepTo, t0 + dur);
  }
  const gain = c.createGain();
  gain.gain.setValueAtTime(0, t0);
  gain.gain.linearRampToValueAtTime(peak, t0 + 0.01);
  gain.gain.exponentialRampToValueAtTime(0.0001, t0 + dur);
  src.connect(filter).connect(gain).connect(c.destination);
  src.start(t0);
}

export function playSound(name: SoundName) {
  const c = ac();
  if (!c) return;
  try {
    switch (name) {
      case "tick":
        tone(c, 1900, "square", 0.035, 0.07);
        break;
      case "coin":
        // Metallischer Doppelton + Glitzer
        tone(c, 2093, "triangle", 0.55, 0.16);
        tone(c, 2637, "triangle", 0.45, 0.1, 0.012);
        tone(c, 3520, "sine", 0.3, 0.05, 0.02);
        break;
      case "dice":
        // Prasselndes Klackern
        [0, 0.09, 0.21, 0.31].forEach((w, i) =>
          noiseBurst(c, 0.05, 0.2 - i * 0.03, 1600 + Math.random() * 1000, w),
        );
        break;
      case "pop":
        tone(c, 420, "sine", 0.14, 0.22, 0, 880);
        break;
      case "whoosh":
        noiseBurst(c, 0.55, 0.1, 500, 0, 2600);
        break;
      case "win":
        // Kleine Fanfare C5–E5–G5–C6
        [523.25, 659.25, 783.99, 1046.5].forEach((f, i) =>
          tone(c, f, "triangle", 0.4, 0.13, i * 0.09),
        );
        break;
    }
  } catch {
    // Sound ist Dekoration – niemals crashen
  }
}
