// Floating Intelligent Audio Player — collapsed pill that expands to reveal track info.
// Uses React context-like state passed via props from App.

const { useEffect, useRef, useState } = React;

function FloatingPlayer({ playerState, setPlayerState }) {
  const { track, isPlaying, expanded } = playerState;
  const [progress, setProgress] = useState(0); // 0..1
  const [duration, setDuration] = useState(0);
  const [loading, setLoading] = useState(false);
  const audioRef = useRef(null);
  const hoverTimerRef = useRef(null);
  const suppressHoverRef = useRef(false);

  // One audio element for the whole page
  useEffect(() => {
    const a = new Audio();
    a.preload = 'metadata'; // solo la ficha del archivo; el audio se descarga al pulsar play
    audioRef.current = a;
    const onTime = () => {
      if (a.duration) setProgress(a.currentTime / a.duration);
    };
    const onMeta = () => { setDuration(a.duration || 0); setLoading(false); };
    const onCanPlay = () => setLoading(false);
    const onErr = () => setLoading(false);
    const onWaiting = () => setLoading(true);
    const onPlaying = () => setLoading(false);
    const onEnd = () => { setProgress(0); setPlayerState(s => ({ ...s, isPlaying: false })); };
    a.addEventListener('timeupdate', onTime);
    a.addEventListener('loadedmetadata', onMeta);
    a.addEventListener('canplay', onCanPlay);
    a.addEventListener('error', onErr);
    a.addEventListener('waiting', onWaiting);
    a.addEventListener('playing', onPlaying);
    a.addEventListener('ended', onEnd);
    return () => { a.pause(); a.src = ''; };
  }, []);

  // Swap source when the track changes
  useEffect(() => {
    const a = audioRef.current;
    if (!a || !track) return;
    const abs = new URL(track.src, location.href).href;
    if (a.src !== abs) {
      a.src = track.src;
      setProgress(0);
      setDuration(0);
      setLoading(true);
      a.load();
    }
  }, [track?.id]);

  // Drive play/pause from state
  useEffect(() => {
    const a = audioRef.current;
    if (!a || !track) return;
    if (isPlaying) {
      const p = a.play();
      if (p && p.catch) p.catch(() => {
        setLoading(false);
        setPlayerState(s => ({ ...s, isPlaying: false }));
      });
    } else {
      a.pause();
    }
  }, [isPlaying, track?.id]);

  const togglePlay = () => {
    setPlayerState(s => ({ ...s, isPlaying: !s.isPlaying }));
  };

  // Colapsar a mano bloquea el hover hasta que el ratón sale del pill,
  // si no el encogimiento vuelve a disparar mouseenter y se reabre solo.
  const collapse = () => {
    if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
    suppressHoverRef.current = true;
    setPlayerState(s => ({ ...s, expanded: false }));
  };
  const expand = () => {
    setPlayerState(s => ({ ...s, expanded: true }));
  };
  const toggleExpand = () => { expanded ? collapse() : expand(); };

  const dismiss = () => {
    if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
    const a = audioRef.current;
    if (a) { a.pause(); a.currentTime = 0; }
    setProgress(0);
    setLoading(false);
    setPlayerState({ track: null, isPlaying: false, expanded: false });
  };

  const seek = (e) => {
    const a = audioRef.current;
    if (!a || !a.duration || !isFinite(a.duration)) return;
    const r = e.currentTarget.getBoundingClientRect();
    const ratio = Math.min(Math.max((e.clientX - r.left) / r.width, 0), 1);
    const target = ratio * a.duration;
    // Algunos servidores no sirven rangos de bytes: si no se puede buscar, no rompas la reproducción.
    const canSeek = a.seekable && a.seekable.length && a.seekable.end(a.seekable.length - 1) > 0;
    if (!canSeek) return;
    try { a.currentTime = target; setProgress(ratio); } catch (err) { /* ignorar */ }
  };

  const handleMouseEnter = () => {
    if (suppressHoverRef.current || expanded) return;
    hoverTimerRef.current = setTimeout(expand, 350);
  };
  const handleMouseLeave = () => {
    if (hoverTimerRef.current) clearTimeout(hoverTimerRef.current);
    suppressHoverRef.current = false;
  };

  const cur = Math.floor((duration || 0) * progress);
  const fmt = (s) => `${Math.floor(s / 60)}:${String(Math.floor(s % 60)).padStart(2, '0')}`;

  if (!track) return null;

  return (
    <div
      className="bi-player fixed bottom-5 right-5 sm:bottom-6 sm:right-6"
      style={{ zIndex: 9999 }}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      <div
        className={`player-shell flex items-center backdrop-blur-md shadow-player ${expanded ? 'pr-4 pl-2' : 'pr-2 pl-2'}`}
        style={{
          width: expanded ? 'min(92vw, 408px)' : '64px',
          height: '64px',
          background: 'rgba(255,255,255,0.78)',
          border: '1px solid rgba(44,75,96,0.10)',
          borderRadius: expanded ? '20px' : '32px',
        }}
      >
        {/* Cover art — always visible */}
        <button
          onClick={toggleExpand}
          className="relative flex-shrink-0 w-12 h-12 rounded-xl overflow-hidden flex items-center justify-center"
          style={{ background: track.coverBg }}
          aria-label={expanded ? 'Colapsar reproductor' : 'Expandir reproductor'}
        >
          <div className="cover-stripes absolute inset-0 opacity-40"></div>
          <CoverGlyph variant={track.coverVariant} small />
          {/* Subtle waveform overlay when playing & collapsed */}
          {isPlaying && !expanded && (
            <div className="absolute inset-0 flex items-center justify-center bg-black/35 text-white">
              <WaveformAnim size={14} />
            </div>
          )}
        </button>

        {/* Expanded content */}
        <div
          className={`flex-1 ml-3 overflow-hidden player-fade ${expanded ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}
          style={{ transform: expanded ? 'translateX(0)' : 'translateX(-8px)' }}
        >
          <div className="flex items-baseline justify-between gap-2">
            <div className="min-w-0">
              <div className="text-[11px] uppercase tracking-[0.14em] text-marca-invisible font-semibold truncate">
                {track.genre}
              </div>
              <div className="text-[13px] font-semibold text-marca-invisible-dark truncate font-display">
                {track.title}
              </div>
              <div className="text-[10px] text-texto-oscuro/55 truncate">Letra de {track.author}</div>
            </div>
            <div className="text-[10px] font-mono text-texto-oscuro/50 flex-shrink-0">
              {duration ? `${fmt(cur)} / ${fmt(duration)}` : (loading ? 'cargando' : '–:–')}
            </div>
          </div>
          {/* Progress bar — click to seek */}
          <div onClick={seek} className="mt-2 h-[3px] bg-marca-invisible/15 rounded-full overflow-hidden" style={{ cursor: 'pointer' }}>
            {loading && isPlaying && progress === 0 ? (
              <div className="h-full bg-marca-banda rounded-full pulse-dot" style={{ width: '30%' }} />
            ) : (
              <div className="h-full bg-marca-banda rounded-full" style={{ width: `${progress * 100}%` }} />
            )}
          </div>
        </div>

        {/* Play/Pause + cerrar — visibles al expandir */}
        {expanded && (
          <button
            onClick={togglePlay}
            className="ml-3 flex-shrink-0 w-10 h-10 rounded-full bg-marca-banda hover:bg-marca-banda-dark text-white flex items-center justify-center transition-colors shadow-md"
            aria-label={isPlaying ? 'Pausar' : 'Reproducir'}
          >
            {isPlaying ? <IconPause size={14} /> : <IconPlay size={14} className="ml-0.5" />}
          </button>
        )}
        {expanded && (
          <button
            onClick={dismiss}
            className="ml-1 flex-shrink-0 w-8 h-8 rounded-full text-texto-oscuro/50 hover:bg-marca-invisible/10 hover:text-marca-invisible-dark flex items-center justify-center transition-colors"
            aria-label="Cerrar reproductor"
            title="Cerrar reproductor"
          >
            <IconClose size={14} />
          </button>
        )}
      </div>

      {/* Tooltip hint on first appearance */}
      {!expanded && (
        <div className="absolute right-full mr-3 top-1/2 -translate-y-1/2 text-[10px] font-mono uppercase tracking-wider text-texto-oscuro/40 whitespace-nowrap hidden sm:block opacity-60">
          {isPlaying ? 'sonando ↗' : ''}
        </div>
      )}
    </div>
  );
}

// Cover glyph — minimal abstract album art (placeholder, no copyrighted imagery)
function CoverGlyph({ variant = 'a', small = false }) {
  const stroke = small ? 1 : 1.4;
  const size = small ? 28 : 44;
  if (variant === 'a') { // indie rock — overlapping circles
    return (
      <svg width={size} height={size} viewBox="0 0 48 48" fill="none" stroke="white" strokeWidth={stroke}>
        <circle cx="19" cy="24" r="11" opacity="0.9"/>
        <circle cx="29" cy="24" r="11" opacity="0.7"/>
      </svg>
    );
  }
  if (variant === 'b') { // acoustic — single vertical line + dot
    return (
      <svg width={size} height={size} viewBox="0 0 48 48" fill="none" stroke="white" strokeWidth={stroke}>
        <path d="M24 8v32" strokeLinecap="round"/>
        <circle cx="24" cy="34" r="5" fill="white"/>
      </svg>
    );
  }
  // 'c' urban — grid
  return (
    <svg width={size} height={size} viewBox="0 0 48 48" fill="none" stroke="white" strokeWidth={stroke}>
      <rect x="10" y="10" width="10" height="10"/>
      <rect x="28" y="10" width="10" height="10"/>
      <rect x="10" y="28" width="10" height="10"/>
      <rect x="28" y="28" width="10" height="10" fill="white"/>
    </svg>
  );
}

function IconClose({ size = 14 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round">
      <path d="M6 6l12 12M18 6L6 18"/>
    </svg>
  );
}

Object.assign(window, { FloatingPlayer, CoverGlyph, IconClose });
