/* global React */
/* useAudio — single source of truth for cassette playback.
   Mounted at the App router level so a song survives a platform shell swap
   (e.g. resizing across the mobile breakpoint mid-track). Both MacShell and
   PhoneShell receive the returned API and thread it into their music UIs. */

const { useState, useEffect, useRef, useCallback } = React;

function useAudio() {
  const audioRef = useRef(null);
  if (!audioRef.current && typeof Audio !== 'undefined') {
    const a = new Audio();
    a.preload = 'none';
    a.crossOrigin = 'anonymous';
    audioRef.current = a;
  }

  const [active, setActive] = useState(null);
  const [paused, setPaused] = useState(true);
  const [progress, setProgress] = useState(0);
  const [duration, setDuration] = useState(0);
  // Holds the pending 2s "tape settling" timer so a re-pick or eject can cancel it.
  const playTimerRef = useRef(null);

  useEffect(() => {
    const a = audioRef.current;
    if (!a) return;
    const onTime = () => setProgress(a.currentTime);
    const onMeta = () => setDuration(a.duration || 0);
    const onPlay = () => setPaused(false);
    const onPause = () => setPaused(true);
    const onEnded = () => setPaused(true);
    a.addEventListener('timeupdate', onTime);
    a.addEventListener('loadedmetadata', onMeta);
    a.addEventListener('play', onPlay);
    a.addEventListener('pause', onPause);
    a.addEventListener('ended', onEnded);
    return () => {
      a.removeEventListener('timeupdate', onTime);
      a.removeEventListener('loadedmetadata', onMeta);
      a.removeEventListener('play', onPlay);
      a.removeEventListener('pause', onPause);
      a.removeEventListener('ended', onEnded);
    };
  }, []);

  const pick = useCallback((data) => {
    const a = audioRef.current;
    if (!a) return;
    setActive(prev => {
      if (prev && prev.id === data.id) return prev;
      if (playTimerRef.current) {
        clearTimeout(playTimerRef.current);
        playTimerRef.current = null;
      }
      a.pause();
      a.src = data.src;
      a.currentTime = 0;
      a.volume = 0.7;
      // Wait for the cassette's insert animation before the song actually starts.
      playTimerRef.current = setTimeout(() => {
        playTimerRef.current = null;
        a.play().catch(() => {});
      }, 2000);
      return data;
    });
  }, []);

  const eject = useCallback(() => {
    const a = audioRef.current;
    if (playTimerRef.current) {
      clearTimeout(playTimerRef.current);
      playTimerRef.current = null;
    }
    if (a) { a.pause(); a.currentTime = 0; }
    setActive(null);
  }, []);

  const togglePlay = useCallback(() => {
    const a = audioRef.current;
    if (!a) return;
    if (playTimerRef.current) {
      clearTimeout(playTimerRef.current);
      playTimerRef.current = null;
    }
    if (a.paused) a.play().catch(() => {});
    else a.pause();
  }, []);

  const seek = useCallback((seconds) => {
    const a = audioRef.current;
    if (!a) return;
    a.currentTime = Math.max(0, Math.min(seconds, a.duration || 0));
  }, []);

  return { active, paused, progress, duration, audio: audioRef.current,
           pick, eject, togglePlay, seek };
}

window.useAudio = useAudio;
