// Sample-based audio layer. Starts only after a real user gesture so browsers do not block playback.
var SFX = {
  throw: { file: './assets/audio/sfx/throw.ogg', volume: 0.36, cooldown: 0.055, jitter: 0.06 },
  bottleImpact: { file: './assets/audio/sfx/bottle_impact.ogg', volume: 0.27, cooldown: 0.045, jitter: 0.08 },
  enemyHit: { file: './assets/audio/sfx/enemy_hit.ogg', volume: 0.31, cooldown: 0.05, jitter: 0.07 },
  pickup: { file: './assets/audio/sfx/pickup.ogg', volume: 0.32, cooldown: 0.08, jitter: 0.02 },
  playerHurt: { file: './assets/audio/sfx/player_hurt.ogg', volume: 0.38, cooldown: 0.24, jitter: 0.04 },
};

var MUSIC_FILE = './assets/audio/music/theme_ancient_caverns.ogg';
var MUSIC_VOLUME = 0.19;

var ctx = null;
var masterGain = null;
var buffers = Object.create(null);
var loading = Object.create(null);
var errors = Object.create(null);
var lastPlay = Object.create(null);
var music = null;
var unlocked = false;
var muted = readMuted();
var unlockCount = 0;

function readMuted() {
  try { return localStorage.getItem('bomzhara_audio_muted') === '1'; }
  catch (e) { return false; }
}

function writeMuted() {
  try { localStorage.setItem('bomzhara_audio_muted', muted ? '1' : '0'); }
  catch (e) {}
}

function url(file) {
  return new URL(file, import.meta.url).href;
}

function ensureContext() {
  if (ctx) return ctx;
  var Ctx = window.AudioContext || window.webkitAudioContext;
  if (!Ctx) return null;
  try {
    ctx = new Ctx();
    masterGain = ctx.createGain();
    masterGain.gain.value = muted ? 0 : 1;
    masterGain.connect(ctx.destination);
  } catch (e) {
    ctx = null;
    masterGain = null;
  }
  return ctx;
}

function ensureMusic() {
  if (music) return music;
  music = new Audio(url(MUSIC_FILE));
  music.loop = true;
  music.preload = 'auto';
  music.volume = muted ? 0 : MUSIC_VOLUME;
  music.muted = muted;
  return music;
}

function decodeAudio(context, arrayBuffer) {
  if (context.decodeAudioData.length <= 1) return context.decodeAudioData(arrayBuffer);
  return new Promise(function (resolve, reject) {
    context.decodeAudioData(arrayBuffer, resolve, reject);
  });
}

function loadSfx(name) {
  if (buffers[name] || loading[name] || errors[name]) return loading[name] || Promise.resolve(buffers[name]);
  var spec = SFX[name];
  var context = ensureContext();
  if (!spec || !context) return Promise.resolve(null);
  loading[name] = fetch(url(spec.file))
    .then(function (res) {
      if (!res.ok) throw new Error('HTTP ' + res.status + ' for ' + spec.file);
      return res.arrayBuffer();
    })
    .then(function (data) { return decodeAudio(context, data); })
    .then(function (buffer) {
      buffers[name] = buffer;
      delete loading[name];
      return buffer;
    })
    .catch(function (err) {
      errors[name] = err && err.message ? err.message : String(err);
      delete loading[name];
      return null;
    });
  return loading[name];
}

export function preloadGameAudio() {
  ensureMusic();
  if (!ensureContext()) return;
  Object.keys(SFX).forEach(loadSfx);
}

export function unlockGameAudio() {
  if (!unlocked) {
    unlocked = true;
    unlockCount++;
  }
  preloadGameAudio();
  if (ctx && ctx.state === 'suspended') ctx.resume().catch(function () {});
  var m = ensureMusic();
  m.muted = muted;
  m.volume = muted ? 0 : MUSIC_VOLUME;
  if (!muted) m.play().catch(function () {});
}

export function playSfx(name, intensity) {
  if (!unlocked || muted) return;
  var spec = SFX[name];
  var context = ensureContext();
  if (!spec || !context || !masterGain) return;
  if (context.state === 'suspended') context.resume().catch(function () {});
  var now = context.currentTime || 0;
  if (lastPlay[name] && now - lastPlay[name] < spec.cooldown) return;
  var buffer = buffers[name];
  if (!buffer) { loadSfx(name); return; }
  lastPlay[name] = now;
  try {
    var src = context.createBufferSource();
    var gain = context.createGain();
    var amt = Math.max(0, Math.min(1.35, intensity == null ? 1 : intensity));
    var pitch = 1 + (Math.random() * 2 - 1) * spec.jitter;
    src.buffer = buffer;
    src.playbackRate.value = pitch;
    gain.gain.value = spec.volume * amt;
    src.connect(gain);
    gain.connect(masterGain);
    src.start();
  } catch (e) {}
}

export function setGameAudioMuted(nextMuted) {
  muted = !!nextMuted;
  writeMuted();
  if (masterGain) masterGain.gain.value = muted ? 0 : 1;
  if (music) {
    music.muted = muted;
    music.volume = muted ? 0 : MUSIC_VOLUME;
    if (!muted && unlocked) music.play().catch(function () {});
  }
  return muted;
}

export function toggleGameAudioMuted() {
  return setGameAudioMuted(!muted);
}

export function audioDebug() {
  return {
    unlocked: unlocked,
    unlockCount: unlockCount,
    muted: muted,
    context: ctx ? ctx.state : 'none',
    loaded: Object.keys(buffers).length,
    pending: Object.keys(loading).length,
    errors: Object.keys(errors).length,
    musicReady: !!music,
    musicPaused: music ? music.paused : true,
  };
}
