// Jai Mahal Audio Tour — Audio playback hook + Player bar
// State lives in the parent (CheckpointScreen) so audio survives read↔listen toggle.

const { useState, useEffect, useRef } = React;

function fmt(s) {
  s = Math.max(0, Math.floor(s));
  const m = Math.floor(s / 60);
  const r = s % 60;
  return `${m}:${String(r).padStart(2, "0")}`;
}

// Real audio hook — uses an HTML <audio> element when `src` is provided.
// Falls back to the RAF-based simulator when src is null/undefined.
// Exposes `duration` which updates from audio metadata once loaded.
function useFakeAudio(durSec, key, src) {
  const [t, setT] = useState(0);
  const [playing, setPlaying] = useState(false);
  const [speed, setSpeed] = useState(1);
  const [duration, setDuration] = useState(durSec); // real dur once metadata loads
  const elRef = useRef(null);

  // Create / replace the <audio> element when src changes.
  useEffect(() => {
    if (!src) { elRef.current = null; setDuration(durSec); return; }
    const el = new Audio(src);
    el.preload = "metadata";
    elRef.current = el;
    return () => { el.pause(); elRef.current = null; };
  }, [src]);

  // Update duration from real audio metadata.
  useEffect(() => {
    const el = elRef.current;
    if (!el) return;
    const onMeta = () => {
      if (isFinite(el.duration) && el.duration > 0) setDuration(Math.ceil(el.duration));
    };
    el.addEventListener("loadedmetadata", onMeta);
    // Already loaded?
    if (isFinite(el.duration) && el.duration > 0) setDuration(Math.ceil(el.duration));
    return () => el.removeEventListener("loadedmetadata", onMeta);
  }, [src]);

  // Sync speed to <audio> element.
  useEffect(() => {
    if (elRef.current) elRef.current.playbackRate = speed;
  }, [speed]);

  // Real audio: mirror element state into React state.
  useEffect(() => {
    const el = elRef.current;
    if (!el) return;
    const onTime  = () => setT(el.currentTime);
    const onEnded = () => { setPlaying(false); setT(el.duration || durSec); };
    const onPlay  = () => setPlaying(true);
    const onPause = () => setPlaying(false);
    el.addEventListener("timeupdate", onTime);
    el.addEventListener("ended",      onEnded);
    el.addEventListener("play",       onPlay);
    el.addEventListener("pause",      onPause);
    return () => {
      el.removeEventListener("timeupdate", onTime);
      el.removeEventListener("ended",      onEnded);
      el.removeEventListener("play",       onPlay);
      el.removeEventListener("pause",      onPause);
    };
  }, [src, durSec]);

  // Reset on chapter change.
  useEffect(() => {
    setT(0);
    setPlaying(false);
    setDuration(durSec);
    if (elRef.current) { elRef.current.pause(); elRef.current.currentTime = 0; }
  }, [key]);

  // Simulated tick — only when no real <audio>.
  useEffect(() => {
    if (elRef.current || !playing) return;
    let last = performance.now();
    let raf;
    const tick = (now) => {
      const dt = (now - last) / 1000;
      last = now;
      setT((p) => {
        const nx = p + dt * speed;
        if (nx >= duration) { setPlaying(false); return duration; }
        return nx;
      });
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [playing, speed, duration, src]);

  const toggle = () => {
    if (elRef.current) {
      elRef.current.paused ? elRef.current.play() : elRef.current.pause();
    } else {
      setPlaying((p) => !p);
    }
  };

  const seekTo = (v) => {
    const clamped = Math.max(0, Math.min(duration, v));
    setT(clamped);
    if (elRef.current) elRef.current.currentTime = clamped;
  };

  return {
    t,
    duration,
    setT: seekTo,
    playing,
    toggle,
    play:  () => elRef.current ? elRef.current.play()  : setPlaying(true),
    pause: () => elRef.current ? elRef.current.pause() : setPlaying(false),
    speed,
    cycleSpeed: () => setSpeed((s) => (s === 1 ? 1.25 : s === 1.25 ? 1.5 : 1)),
    skip: (delta) => {
      if (elRef.current) {
        const el = elRef.current;
        el.currentTime = Math.max(0, Math.min(el.duration || duration, el.currentTime + delta));
      } else {
        setT((p) => Math.max(0, Math.min(duration, p + delta)));
      }
    },
  };
}

// ─── Player bar ───────────────────────────────────────────────────────────────
// Layout:
//   [progress bar + scrubber]
//   [0:00                  3:00]
//   [Home] [⏮Prev] [←10s] [▶Play] [10s→] [Next⏭] [Read]
function PlayerBar({ ch, audio, onHome, onPrev, onNext, mode, setMode }) {
  const seekRef = useRef(null);
  const dur = audio.duration || ch.durSec;

  const draggingRef = useRef(false);

  const seekAt = (clientX) => {
    const r = seekRef.current.getBoundingClientRect();
    const ratio = Math.max(0, Math.min(1, (clientX - r.left) / r.width));
    audio.setT(ratio * dur);
  };

  const onPointerDown = (e) => {
    draggingRef.current = true;
    try { e.currentTarget.setPointerCapture(e.pointerId); } catch (_) {}
    seekAt(e.clientX);
  };
  const onPointerMove = (e) => {
    if (!draggingRef.current) return;
    seekAt(e.clientX);
  };
  const onPointerUp = (e) => {
    draggingRef.current = false;
    try { e.currentTarget.releasePointerCapture(e.pointerId); } catch (_) {}
  };

  const prevDisabled = ch.id === 1;
  const inRead = mode === "read";
  const pct = dur > 0 ? (audio.t / dur) * 100 : 0;

  return (
    <footer
      style={{
        position: "relative",
        background: "var(--cream)",
        borderTop: "1px solid var(--border)",
        flexShrink: 0,
      }}
    >
      {/* ── Seek bar (drag-able) ── */}
      <div
        ref={seekRef}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
        style={{
          position: "relative",
          height: 32,
          padding: "16px 22px 0",
          cursor: "pointer",
          touchAction: "none",
          userSelect: "none",
        }}
      >
        <div
          style={{
            position: "relative",
            height: 3,
            background: "var(--ink-faint-2)",
            borderRadius: 2,
            overflow: "visible",
          }}
        >
          <div
            style={{
              position: "absolute",
              left: 0, top: 0, bottom: 0,
              width: `${pct}%`,
              background: "var(--gold-dark)",
              borderRadius: 2,
              transition: draggingRef.current ? "none" : "width .12s linear",
            }}
          />
          <div
            style={{
              position: "absolute",
              left: `${pct}%`,
              top: "50%",
              transform: "translate(-50%, -50%)",
              width: 14, height: 14,
              borderRadius: "50%",
              background: "var(--gold-dark)",
              boxShadow: "0 1px 5px rgba(168,138,78,0.55)",
              transition: draggingRef.current ? "none" : "left .12s linear",
            }}
          />
        </div>
      </div>

      {/* ── Time labels ── */}
      <div
        style={{
          display: "flex",
          justifyContent: "space-between",
          padding: "4px 24px 0",
          fontFamily: "var(--font-sans)",
          fontSize: 10,
          color: "var(--ink-soft)",
          letterSpacing: 0.5,
          fontVariantNumeric: "tabular-nums",
        }}
      >
        <span>{fmt(audio.t)}</span>
        <span>{fmt(dur)}</span>
      </div>

      {/* ── Controls row ── */}
      <div
        style={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
          padding: "6px 14px 16px",
        }}
      >
        {/* Speed */}
        <SpeedBtn speed={audio.speed} onClick={audio.cycleSpeed} />

        {/* Previous chapter */}
        <CtrlBtn label="Prev" onClick={onPrev} disabled={prevDisabled} size="sm">
          <Icon.ChapterBack size={20} />
        </CtrlBtn>

        {/* ← 10 s */}
        <CtrlBtn label="−10s" onClick={() => audio.skip(-10)} size="sm">
          <Icon.SkipBack size={22} />
        </CtrlBtn>

        {/* Play / Pause — hero button */}
        <button
          onClick={audio.toggle}
          aria-label={audio.playing ? "Pause" : "Play"}
          style={{
            width: 56,
            height: 56,
            borderRadius: "50%",
            background: "var(--ink)",
            color: "var(--cream)",
            border: "none",
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            cursor: "pointer",
            boxShadow: "0 6px 22px rgba(34,23,16,0.25)",
            flexShrink: 0,
            transition: "transform .12s",
          }}
        >
          {audio.playing ? <Icon.Pause size={20} /> : <Icon.Play size={20} />}
        </button>

        {/* +10 s */}
        <CtrlBtn label="+10s" onClick={() => audio.skip(10)} size="sm">
          <Icon.SkipFwd size={22} />
        </CtrlBtn>

        {/* Next chapter */}
        <CtrlBtn label="Next" onClick={onNext} size="sm">
          <Icon.ChapterFwd size={20} />
        </CtrlBtn>

        {/* Read / Listen toggle */}
        <CtrlBtn
          label={inRead ? "Listen" : "Read"}
          onClick={() => setMode(inRead ? "listen" : "read")}
          active={inRead}
          size="sm"
        >
          {inRead ? <Icon.Headphones size={18} /> : <Icon.Book size={18} />}
        </CtrlBtn>
      </div>
    </footer>
  );
}

// Playback speed button — cycles 1× → 1.25× → 1.5×
function SpeedBtn({ speed, onClick }) {
  const label = speed === 1 ? "1×" : speed === 1.25 ? "1.25×" : "1.5×";
  return (
    <button
      onClick={onClick}
      aria-label={`Playback speed ${label}`}
      style={{
        background: "transparent",
        border: "1px solid var(--gold-dark)",
        color: "var(--gold-dark)",
        cursor: "pointer",
        width: 40,
        height: 40,
        borderRadius: 20,
        fontFamily: "var(--font-sans)",
        fontSize: speed === 1 ? 13 : 10,
        fontWeight: 700,
        letterSpacing: 0,
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        flexShrink: 0,
        padding: 0,
        transition: "background .15s, color .15s",
      }}
    >
      {label}
    </button>
  );
}

// (legacy SkipChip kept for backward compat — unused)
function SkipChip({ dir }) {
  const isFwd = dir === "fwd";
  return (
    <div
      style={{
        display: "flex",
        alignItems: "center",
        gap: 1,
        fontFamily: "var(--font-sans)",
        fontWeight: 700,
        fontSize: 13,
        lineHeight: 1,
        color: "currentColor",
      }}
    >
      {!isFwd && (
        <svg width={9} height={11} viewBox="0 0 9 11" fill="currentColor">
          <path d="M9 0v11L0 5.5z" />
        </svg>
      )}
      <span style={{ letterSpacing: -0.5 }}>10</span>
      {isFwd && (
        <svg width={9} height={11} viewBox="0 0 9 11" fill="currentColor">
          <path d="M0 0l9 5.5L0 11z" />
        </svg>
      )}
    </div>
  );
}

function CtrlBtn({ children, onClick, label, disabled, active, size = "md" }) {
  const dim = size === "sm" ? 40 : 44;
  return (
    <button
      onClick={onClick}
      aria-label={label}
      disabled={disabled}
      style={{
        background: active ? "var(--cream-2)" : "transparent",
        border: "none",
        cursor: disabled ? "default" : "pointer",
        color: active ? "var(--ink)" : disabled ? "var(--ink-faint-2)" : "var(--ink-soft)",
        width: dim,
        height: dim,
        borderRadius: "50%",
        display: "flex",
        flexDirection: "column",
        alignItems: "center",
        justifyContent: "center",
        gap: 1,
        flexShrink: 0,
        padding: 0,
        transition: "background .15s, color .15s",
      }}
    >
      {children}
      <span
        style={{
          fontFamily: "var(--font-sans)",
          fontSize: 6.5,
          letterSpacing: 1.2,
          textTransform: "uppercase",
          marginTop: 1,
          opacity: 0.85,
        }}
      >
        {label}
      </span>
    </button>
  );
}

Object.assign(window, { useFakeAudio, PlayerBar, fmt });
