// Selectable notification sounds, generated procedurally with the Web Audio API
// (no asset files — same approach as the original guest-order chime, keeps the
// dashboard fully offline-capable). Each preset is a small list of tones.

export type SoundId = "classic" | "ding" | "bell" | "chime" | "marimba" | "alert";

export const DEFAULT_SOUND_ID: SoundId = "classic";

/** Order shown in the settings sound picker. `labelKey` resolves under `notifPrefs`. */
export const SOUND_PRESETS: { id: SoundId; labelKey: string }[] = [
  { id: "classic", labelKey: "soundClassic" },
  { id: "ding", labelKey: "soundDing" },
  { id: "bell", labelKey: "soundBell" },
  { id: "chime", labelKey: "soundChime" },
  { id: "marimba", labelKey: "soundMarimba" },
  { id: "alert", labelKey: "soundAlert" },
];

type Tone = {
  freq: number;
  /** Start offset in seconds. */
  at: number;
  /** Duration in seconds. */
  dur: number;
  type?: OscillatorType;
  /** Peak gain before the volume multiplier (0..1). */
  peak?: number;
};

const RECIPES: Record<SoundId, Tone[]> = {
  classic: [
    { freq: 880, at: 0, dur: 0.25 },
    { freq: 1175, at: 0.18, dur: 0.27 },
  ],
  ding: [{ freq: 1318, at: 0, dur: 0.4, peak: 0.3 }],
  bell: [
    { freq: 1568, at: 0, dur: 0.6, peak: 0.28 },
    { freq: 2349, at: 0, dur: 0.4, peak: 0.12 },
  ],
  chime: [
    { freq: 783, at: 0, dur: 0.3 },
    { freq: 987, at: 0.12, dur: 0.3 },
    { freq: 1318, at: 0.24, dur: 0.4 },
  ],
  marimba: [
    { freq: 659, at: 0, dur: 0.18, type: "triangle", peak: 0.3 },
    { freq: 1318, at: 0, dur: 0.12, type: "sine", peak: 0.1 },
  ],
  alert: [
    { freq: 988, at: 0, dur: 0.18, type: "square", peak: 0.18 },
    { freq: 988, at: 0.22, dur: 0.18, type: "square", peak: 0.18 },
  ],
};

/**
 * Play a notification sound. `volume` is 0..1. Silently no-ops if the browser
 * blocks the audio context (private mode, no user gesture yet, etc.).
 */
export function playSound(id: SoundId, volume = 0.7): void {
  if (typeof window === "undefined") return;
  const clamped = Math.max(0, Math.min(1, volume));
  if (clamped <= 0) return;
  try {
    const Ctx =
      window.AudioContext ||
      (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;
    if (!Ctx) return;
    const ctx = new Ctx();
    const tones = RECIPES[id] ?? RECIPES.classic;
    let maxEnd = 0;
    for (const { freq, at, dur, type = "sine", peak = 0.25 } of tones) {
      const o = ctx.createOscillator();
      const g = ctx.createGain();
      o.connect(g);
      g.connect(ctx.destination);
      o.type = type;
      o.frequency.value = freq;
      const t0 = ctx.currentTime + at;
      g.gain.setValueAtTime(0.0001, t0);
      g.gain.exponentialRampToValueAtTime(Math.max(0.0001, peak * clamped), t0 + 0.02);
      g.gain.exponentialRampToValueAtTime(0.0001, t0 + dur);
      o.start(t0);
      o.stop(t0 + dur + 0.02);
      maxEnd = Math.max(maxEnd, at + dur);
    }
    setTimeout(() => void ctx.close().catch(() => {}), (maxEnd + 0.3) * 1000);
  } catch {
    // audio blocked — callers fall back to toast / desktop notification
  }
}
