// Background music — presenter-only floating player.
// Streams an actual track via a hidden YouTube IFrame player. The track URL
// comes from window.TWEAK_DEFAULTS.musicTrack (any normal YouTube share URL).
// Auto-loops; presenter controls play/stop/volume; auto-follows phase suggestions.

// ── Phase → music suggestion map ───────────────────────────────────────────
const PHASE_MUSIC = {
  welcome:           { suggest: "on",     note: "Arrival mood — turn off when you start speaking" },
  snapshot:          { suggest: "on",     note: "Bed while they answer the snapshot questions" },
  "snapshot-result": { suggest: "off",    note: "Hold space for the reveal — silence carries weight" },
  movie:             { suggest: "on",     note: "Underscore the day-in-life — stop when you transition" },
  reality:           { suggest: "low",    note: "Quiet bed — turn down further when you speak" },
  teach:             { suggest: "off",    note: "Presentation slides — no music" },
  recognise:         { suggest: "on",     note: "While they identify their stress signals" },
  exhale:            { suggest: "off",    note: "Breathing exercise has its own rhythm — no music" },
  simplify:          { suggest: "on",     note: "Sorting the load — gentle bed" },
  establish:         { suggest: "on",     note: "Choosing their phrase — gentle bed" },
  take:              { suggest: "on",     note: "While they write their next step" },
  guided:            { suggest: "off",    note: "Anchor word — silence is the point" },
  plan:              { suggest: "manual", note: "Toggle on while they fill in their plan" },
  close:             { suggest: "manual", note: "Your call — most presenters leave this quiet" },
  faq:               { suggest: "manual", note: "Your call" },
};

// ── Helpers ────────────────────────────────────────────────────────────────
function extractYouTubeId(url) {
  if (!url || typeof url !== "string") return null;
  // Already an ID?
  if (/^[A-Za-z0-9_-]{11}$/.test(url.trim())) return url.trim();
  try {
    const u = new URL(url);
    if (u.hostname.includes("youtu.be")) {
      const id = u.pathname.split("/").filter(Boolean)[0];
      return id || null;
    }
    if (u.hostname.includes("youtube.com") || u.hostname.includes("youtube-nocookie.com")) {
      const v = u.searchParams.get("v");
      if (v) return v;
      const parts = u.pathname.split("/").filter(Boolean);
      if ((parts[0] === "embed" || parts[0] === "shorts" || parts[0] === "live") && parts[1]) {
        return parts[1];
      }
    }
  } catch (_) {}
  return null;
}

// ── YT IFrame API loader (singleton) ──────────────────────────────────────
let ytApiPromise = null;
function loadYTApi() {
  if (ytApiPromise) return ytApiPromise;
  ytApiPromise = new Promise((resolve) => {
    if (window.YT && window.YT.Player) { resolve(window.YT); return; }
    const prev = window.onYouTubeIframeAPIReady;
    window.onYouTubeIframeAPIReady = function () {
      if (typeof prev === "function") { try { prev(); } catch (_) {} }
      resolve(window.YT);
    };
    const s = document.createElement("script");
    s.src = "https://www.youtube.com/iframe_api";
    s.async = true;
    document.head.appendChild(s);
  });
  return ytApiPromise;
}

// ── useYouTubeMusic hook ──────────────────────────────────────────────────
function useYouTubeMusic(videoId, initialVolume = 0.35) {
  const containerRef = React.useRef(null);
  const playerRef = React.useRef(null);
  const [playing, setPlaying] = React.useState(false);
  const [volume, setVolumeState] = React.useState(initialVolume);
  const [started, setStarted] = React.useState(false);
  const [ready, setReady] = React.useState(false);
  const [error, setError] = React.useState(null);

  // (Re)create player when videoId changes
  React.useEffect(() => {
    if (!containerRef.current || !videoId) return;
    let cancelled = false;
    setReady(false);
    setError(null);

    loadYTApi().then((YT) => {
      if (cancelled || !containerRef.current) return;
      // Clean up any prior player
      if (playerRef.current) {
        try { playerRef.current.destroy(); } catch (_) {}
        playerRef.current = null;
      }
      containerRef.current.innerHTML = "";
      const div = document.createElement("div");
      containerRef.current.appendChild(div);

      playerRef.current = new YT.Player(div, {
        videoId,
        width: "320",
        height: "180",
        host: "https://www.youtube-nocookie.com",
        playerVars: {
          autoplay: 0,
          controls: 0,
          loop: 1,
          playlist: videoId,    // required for loop=1 on a single video
          modestbranding: 1,
          disablekb: 1,
          fs: 0,
          rel: 0,
          iv_load_policy: 3,
          playsinline: 1,
        },
        events: {
          onReady: (e) => {
            if (cancelled) return;
            setReady(true);
            try { e.target.setVolume(Math.round(initialVolume * 100)); } catch (_) {}
          },
          onStateChange: (e) => {
            // 0=ended, 1=playing, 2=paused, 3=buffering, 5=cued
            if (e.data === 1) setPlaying(true);
            else if (e.data === 2) setPlaying(false);
            else if (e.data === 0) {
              // Loop fallback if loop param doesn't fire (older clients)
              try { e.target.seekTo(0); e.target.playVideo(); } catch (_) {}
            }
          },
          onError: (e) => {
            // 2=bad ID, 5=HTML5 issue, 100=removed/private, 101/150=embed disabled
            const msg = ({
              2:   "That video URL doesn't look right.",
              5:   "Couldn't play this track here.",
              100: "Track is private or removed.",
              101: "This track's owner has disabled off-YouTube playback. Pick another.",
              150: "This track's owner has disabled off-YouTube playback. Pick another.",
            })[e.data] || ("Couldn't load track (code " + e.data + ").");
            setError(msg);
          },
        },
      });
    });

    return () => {
      cancelled = true;
      if (playerRef.current) {
        try { playerRef.current.destroy(); } catch (_) {}
        playerRef.current = null;
      }
    };
  }, [videoId]);  // eslint-disable-line

  const play = React.useCallback(() => {
    if (!playerRef.current || !ready) return;
    try {
      playerRef.current.setVolume(Math.round(volume * 100));
      playerRef.current.unMute();
      playerRef.current.playVideo();
      setStarted(true);
    } catch (_) {}
  }, [ready, volume]);

  const stop = React.useCallback(() => {
    if (!playerRef.current) return;
    try { playerRef.current.pauseVideo(); } catch (_) {}
  }, []);

  const setVolume = React.useCallback((v) => {
    const vol = Math.max(0, Math.min(1, v));
    setVolumeState(vol);
    if (playerRef.current) {
      try { playerRef.current.setVolume(Math.round(vol * 100)); } catch (_) {}
    }
  }, []);

  return { containerRef, playing, volume, started, ready, error, play, stop, setVolume };
}

// ── MusicPlayer floating widget ───────────────────────────────────────────
function MusicPlayer({ phase }) {
  // Live-read the URL from tweaks so it updates without remount
  const [trackUrl, setTrackUrl] = React.useState(
    () => (window.TWEAK_DEFAULTS && window.TWEAK_DEFAULTS.musicTrack) || ""
  );
  React.useEffect(() => {
    const onChange = (e) => {
      const next = (e && e.detail && e.detail.musicTrack);
      if (next !== undefined) setTrackUrl(next || "");
    };
    window.addEventListener("tweakchange", onChange);
    return () => window.removeEventListener("tweakchange", onChange);
  }, []);

  const videoId = React.useMemo(() => extractYouTubeId(trackUrl), [trackUrl]);
  const {
    containerRef, playing, volume, started, ready, error,
    play, stop, setVolume,
  } = useYouTubeMusic(videoId, 0.35);

  const [autoFollow, setAutoFollow] = React.useState(true);
  const [open, setOpen] = React.useState(true);
  const prevPhaseRef = React.useRef(phase);
  const suggestion = PHASE_MUSIC[phase] || { suggest: "manual", note: "" };

  // Auto-follow phase changes — only after presenter has hit play once
  React.useEffect(() => {
    if (prevPhaseRef.current === phase) return;
    prevPhaseRef.current = phase;
    if (!autoFollow || !started || !ready) return;
    if (suggestion.suggest === "on") {
      setVolume(0.45);
      play();
    } else if (suggestion.suggest === "low") {
      setVolume(0.22);
      play();
    } else if (suggestion.suggest === "off") {
      stop();
    }
  }, [phase, autoFollow, started, ready, suggestion.suggest, play, stop, setVolume]);

  const togglePlay = () => (playing ? stop() : play());

  const suggestColor =
    suggestion.suggest === "on"     ? "var(--terra)" :
    suggestion.suggest === "low"    ? "#8E8C2C" :
    suggestion.suggest === "off"    ? "var(--ink-3)" :
                                      "#5A6E5E";
  const suggestLabel =
    suggestion.suggest === "on"     ? "MUSIC ON" :
    suggestion.suggest === "low"    ? "QUIET BED" :
    suggestion.suggest === "off"    ? "QUIET" :
                                      "MANUAL";

  // Hidden iframe lives off-screen; audio still routes to speakers.
  const hiddenIframeStyle = {
    position: "fixed",
    left: "-9999px",
    top: "-9999px",
    width: "320px",
    height: "180px",
    opacity: 0,
    pointerEvents: "none",
  };

  if (!open) {
    return (
      <>
        <div ref={containerRef} style={hiddenIframeStyle} aria-hidden="true" />
        <button
          className="mp-pill"
          onClick={() => setOpen(true)}
          aria-label="Open music controls"
        >
          ♪ {playing ? "Playing" : "Music"}
        </button>
      </>
    );
  }

  return (
    <>
      <div ref={containerRef} style={hiddenIframeStyle} aria-hidden="true" />
      <div className="mp">
        <div className="mp-head">
          <div className="mp-title">
            <span className="mp-icon">♪</span>
            <span>Background music</span>
          </div>
          <button className="mp-min" onClick={() => setOpen(false)} aria-label="Minimise">
            –
          </button>
        </div>

        {!videoId && (
          <div className="mp-warn">
            No track set. Open <strong>Tweaks</strong> and paste a YouTube
            share URL into <code>musicTrack</code>.
          </div>
        )}
        {videoId && error && (
          <div className="mp-warn">{error}</div>
        )}
        {videoId && !ready && !error && (
          <div className="mp-loading">Loading track…</div>
        )}

        <button
          className={`mp-play ${playing ? "is-playing" : ""}`}
          onClick={togglePlay}
          disabled={!ready || !!error}
          aria-label={playing ? "Stop music" : "Play music"}
        >
          {playing ? (
            <>
              <span className="mp-play-icon">■</span>
              <span>Stop</span>
            </>
          ) : (
            <>
              <span className="mp-play-icon">▶</span>
              <span>Play</span>
            </>
          )}
        </button>

        <div className="mp-vol">
          <label className="mp-vol-label">Volume</label>
          <input
            type="range"
            min="0"
            max="100"
            value={Math.round(volume * 100)}
            onChange={(e) => setVolume(Number(e.target.value) / 100)}
            className="mp-vol-slider"
            aria-label="Music volume"
          />
          <span className="mp-vol-val">{Math.round(volume * 100)}</span>
        </div>

        <div className="mp-suggest" style={{ borderColor: suggestColor }}>
          <div className="mp-suggest-chip" style={{ background: suggestColor }}>
            {suggestLabel}
          </div>
          <div className="mp-suggest-note">{suggestion.note}</div>
        </div>

        <label className="mp-auto">
          <input
            type="checkbox"
            checked={autoFollow}
            onChange={(e) => setAutoFollow(e.target.checked)}
          />
          <span>Follow phase suggestions automatically</span>
        </label>

        {!started && ready && (
          <div className="mp-tip">
            Tip: click <strong>Play</strong> once at the start. After that, the
            music will fade in/out automatically as you move through phases — and
            you can always override here.
          </div>
        )}
      </div>
    </>
  );
}

Object.assign(window, { MusicPlayer, useYouTubeMusic, PHASE_MUSIC, extractYouTubeId });
