// Single-element global audio player. One <audio> created lazily and reused
// across screens — the queue, decided list, anywhere we need to preview a
// submission. State (currentId, position, volume) is observable via useAudio()
// so any component can render against it.
//
// Volume persists in localStorage so the user's setting survives reloads.

const VOLUME_KEY = 'storytime.volume';

const AudioService = (() => {
  let el = null;
  let state = {
    currentId: null,
    pos: 0,
    duration: 0,
    volume: (() => {
      const raw = parseFloat(localStorage.getItem(VOLUME_KEY));
      return isFinite(raw) && raw >= 0 && raw <= 1 ? raw : 0.8;
    })(),
  };
  const subs = new Set();
  const emit = () => subs.forEach(fn => fn(state));

  function ensureEl() {
    if (el) return el;
    el = document.createElement('audio');
    el.preload = 'auto';
    el.volume = state.volume;
    el.addEventListener('timeupdate', () => {
      state = { ...state, pos: el.currentTime, duration: el.duration || state.duration };
      emit();
    });
    el.addEventListener('loadedmetadata', () => {
      state = { ...state, duration: el.duration || 0 };
      emit();
    });
    el.addEventListener('ended', () => {
      state = { ...state, currentId: null, pos: 0 };
      emit();
    });
    el.addEventListener('pause', () => {
      // External pause → reflect "stopped" UI state when fully paused, but
      // keep currentId so the user can resume by clicking the same row again.
    });
    document.body.appendChild(el);
    return el;
  }

  // Toggle play/pause on the same id; otherwise switch.
  function play(id, url) {
    const e = ensureEl();
    if (state.currentId === id) {
      if (e.paused) e.play().catch(() => {});
      else e.pause();
      // currentId becomes null only on explicit stop (different id) or 'ended'.
      // Pause leaves it set so the same row's button keeps the "playing" look
      // — reflect that via paused state in consumers if needed.
      state = { ...state, currentId: e.paused ? null : id };
      emit();
      return;
    }
    if (!url) return;
    e.src = url;
    e.currentTime = 0;
    state = { ...state, currentId: id, pos: 0, duration: 0 };
    e.play().catch(() => {});
    emit();
  }

  function stop() {
    if (el) el.pause();
    state = { ...state, currentId: null, pos: 0 };
    emit();
  }

  function seek(seconds) {
    if (!el) return;
    const max = el.duration || seconds;
    const safe = Math.max(0, Math.min(max, seconds));
    el.currentTime = safe;
    state = { ...state, pos: safe };
    emit();
  }

  function setVolume(v) {
    const safe = Math.max(0, Math.min(1, v));
    if (el) el.volume = safe;
    localStorage.setItem(VOLUME_KEY, String(safe));
    state = { ...state, volume: safe };
    emit();
  }

  return {
    play, stop, seek, setVolume,
    get: () => state,
    subscribe: (fn) => { subs.add(fn); return () => subs.delete(fn); },
  };
})();

window.AudioService = AudioService;

// React hook — returns current state + bound action helpers.
function useAudio() {
  const [s, setS] = React.useState(AudioService.get());
  React.useEffect(() => AudioService.subscribe(setS), []);
  return {
    ...s,
    play: AudioService.play,
    stop: AudioService.stop,
    seek: AudioService.seek,
    setVolume: AudioService.setVolume,
  };
}
window.useAudio = useAudio;
