export type SoundTheme = "spark" | "bubble" | "arcade" | "calm";

export const SOUND_THEMES: Array<{ id: SoundTheme; label: string; note: string }> = [
  { id: "spark", label: "按钮点击", note: "arcade-game-jump-coin" },
  { id: "bubble", label: "答对反馈", note: "correct-answer-tone" },
  { id: "arcade", label: "答错反馈", note: "game-show-buzz-in" },
  { id: "calm", label: "游戏完成", note: "fairy-arcade-sparkle" },
];

const STORAGE_KEY = "brain-h5-sound-theme";
const ENABLED_KEY = "brain-h5-sound-enabled";

const SOUND_FILES = {
  tap: "/assets/sounds/click.wav",
  correct: "/assets/sounds/correct.wav",
  wrong: "/assets/sounds/wrong.wav",
  complete: "/assets/sounds/complete.wav",
  countdown: "/assets/sounds/click.wav",
} as const;

const audioCache = new Map<string, HTMLAudioElement>();
let audioContext: AudioContext | null = null;
const bufferCache = new Map<string, AudioBuffer>();

function getAudio(path: string) {
  const cached = audioCache.get(path);
  if (cached) return cached;
  const audio = new Audio(path);
  audio.preload = "auto";
  audioCache.set(path, audio);
  return audio;
}

export async function preloadSounds() {
  if (typeof window === "undefined") return;
  if (!audioContext) audioContext = new AudioContext();
  await Promise.all(Object.values(SOUND_FILES).map(async (path) => {
    if (bufferCache.has(path)) return;
    try {
      const response = await fetch(path);
      const data = await response.arrayBuffer();
      const buffer = await audioContext!.decodeAudioData(data);
      bufferCache.set(path, buffer);
    } catch {
      // HTMLAudioElement fallback in playSound handles slow/unsupported devices.
    }
  }));
}

export function getSoundTheme(): SoundTheme {
  const value = window.localStorage.getItem(STORAGE_KEY);
  return SOUND_THEMES.some((theme) => theme.id === value) ? value as SoundTheme : "spark";
}

export function setSoundTheme(theme: SoundTheme) {
  window.localStorage.setItem(STORAGE_KEY, theme);
}

export function isSoundEnabled() {
  return window.localStorage.getItem(ENABLED_KEY) !== "false";
}

export function setSoundEnabled(enabled: boolean) {
  window.localStorage.setItem(ENABLED_KEY, String(enabled));
}

export function playSound(kind: "tap" | "correct" | "wrong" | "complete" | "countdown", _theme = getSoundTheme()) {
  if (!isSoundEnabled()) return;
  const path = SOUND_FILES[kind];
  const buffer = bufferCache.get(path);
  if (buffer && audioContext) {
    if (audioContext.state === "suspended") void audioContext.resume();
    const source = audioContext.createBufferSource();
    const gain = audioContext.createGain();
    gain.gain.value = kind === "wrong" ? 0.58 : kind === "complete" ? 0.72 : 0.66;
    source.buffer = buffer;
    source.connect(gain).connect(audioContext.destination);
    source.start(0);
    return;
  }
  const audio = getAudio(path);
  audio.currentTime = 0;
  audio.volume = kind === "wrong" ? 0.58 : kind === "complete" ? 0.72 : 0.66;
  void audio.play().catch(() => undefined);
}

export function previewSound(theme: SoundTheme) {
  setSoundEnabled(true);
  setSoundTheme(theme);
  const previewKind: Record<SoundTheme, "tap" | "correct" | "wrong" | "complete"> = {
    spark: "tap",
    bubble: "correct",
    arcade: "wrong",
    calm: "complete",
  };
  playSound(previewKind[theme], theme);
}
