// Story shell: chrome (progress, beat counter, share), nav (tap zones,
// keyboard), auto-advance timer, and the Tweaks panel integration.

const { useState: useStateShell, useEffect: useEffectShell, useRef: useRefShell, useMemo: useMemoShell } = React;

/* =========================================================
   Stage mode — portrait phone canvas on small screens, wide
   landscape canvas on desktop. The card fills available space;
   beats reflow into two columns via the .landscape class.
   ========================================================= */
function useStageScale() {
  const [mode, setMode] = useStateShell({ w: 480, h: 854, scale: 1, landscape: false });
  useEffectShell(() => {
    const recalc = () => {
      const vw = window.innerWidth,vh = window.innerHeight;
      const landscape = vw >= 1000;
      const mobile = vw < 768;
      const railWidth = vw >= 1100 ? 300 : 0;
      const padX = landscape ? 40 : (mobile ? 0 : 18);
      const padY = landscape ? 104 : (mobile ? 0 : 116);
      const availW = Math.max(280, vw - railWidth - padX * 2);
      const availH = Math.max(360, vh - padY);
      let W, H, scale;
      if (landscape) {
        W = Math.min(1320, availW);
        H = Math.min(820, availH);
        if (W / H < 1.25) H = Math.round(W / 1.25);
        scale = Math.min(1, availW / W, availH / H);
      } else {
        W = 480;H = 854;
        scale = Math.min(1.35, Math.max(0.4, Math.min(availW / W, availH / H)));
      }
      setMode({ w: W, h: H, scale, landscape });
    };
    recalc();
    window.addEventListener("resize", recalc);
    return () => window.removeEventListener("resize", recalc);
  }, []);
  return mode;
}

/* =========================================================
   Toast — small status notification for share actions.
   ========================================================= */
function useToast() {
  const [msg, setMsg] = useStateShell("");
  const tRef = useRefShell(null);
  const show = (text) => {
    setMsg(text);
    clearTimeout(tRef.current);
    tRef.current = setTimeout(() => setMsg(""), 1800);
  };
  useEffectShell(() => () => clearTimeout(tRef.current), []);
  return [msg, show];
}

/* =========================================================
   StoryViewer — the whole experience.
   ========================================================= */
function StoryViewer({ tweaks }) {
  const story = window.STORY_DATA;
  const beats = story.beats;
  const [idx, setIdx] = useStateShell(0);
  const [playing, setPlaying] = useStateShell(false);
  const [progress, setProgress] = useStateShell(0); // 0..1 inside current beat
  const [toastMsg, showToast] = useToast();
  const tickRef = useRefShell(null);
  const lastTRef = useRefShell(null);

  // Speed multiplier — user-tunable via the pill UI. Cycles through 0.7 / 1.0 / 1.3 / 1.7.
  const SPEEDS = [0.7, 1.0, 1.3, 1.7];
  const [speedIdx, setSpeedIdx] = useStateShell(1); // default 1.0×
  const speedMul = SPEEDS[speedIdx];
  const cycleSpeed = () => setSpeedIdx((i) => (i + 1) % SPEEDS.length);

  // Per-beat ms based on word count. Interactive beats get a fixed long window
  // because the user is meant to engage with them.
  const beatWords = (beat) => {
    const arr = [];
    ["title", "body", "attribution"].forEach((k) => { if (beat[k]) arr.push(beat[k]); });
    if (beat.items) arr.push(...beat.items);
    if (beat.stat && beat.stat.caption) arr.push(beat.stat.caption);
    if (beat.walker) {
      (beat.walker.shared || []).forEach((s) => { arr.push(s.title || ""); arr.push(s.body || ""); });
      const branches = beat.walker.branches || {};
      Object.keys(branches).forEach((k) => {
        (branches[k].steps || []).forEach((s) => { arr.push(s.title || ""); arr.push(s.body || ""); });
      });
    }
    return arr.join(" ").split(/\s+/).filter((w) => w.length > 0).length;
  };
  const INTERACTIVE_TYPES = ["walker", "fanout", "graph", "centroid", "passage", "influencemap", "distribute"];
  const beatMs = (() => {
    const beat = beats[idx];
    const interactive = INTERACTIVE_TYPES.indexOf(beat.type) >= 0;
    const base = interactive ? 22000 : Math.max(4000, beatWords(beat) * 320);
    return base / speedMul;
  })();

  const go = (next) => {
    setProgress(0);
    setIdx((i) => Math.max(0, Math.min(beats.length - 1, next)));
  };
  const next = () => go(idx + 1);
  const prev = () => go(idx - 1);

  // Keyboard nav
  useEffectShell(() => {
    const onKey = (e) => {
      if (e.key === "ArrowRight" || e.key === " ") {e.preventDefault();next();} else
      if (e.key === "ArrowLeft") prev();else
      if (e.key === "Escape") setPlaying(false);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  });

  // Auto-advance ticker
  useEffectShell(() => {
    if (!playing) {
      cancelAnimationFrame(tickRef.current);
      lastTRef.current = null;
      return;
    }
    const tick = (t) => {
      if (!lastTRef.current) lastTRef.current = t;
      const dt = t - lastTRef.current;
      lastTRef.current = t;
      setProgress((p) => {
        const np = p + dt / beatMs;
        if (np >= 1) {
          if (idx < beats.length - 1) {
            setIdx((i) => i + 1);
            return 0;
          } else {
            setPlaying(false);
            return 1;
          }
        }
        return np;
      });
      tickRef.current = requestAnimationFrame(tick);
    };
    tickRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(tickRef.current);
  }, [playing, idx, beatMs, beats.length]);

  // When index changes, reset progress timer source.
  useEffectShell(() => {lastTRef.current = null;}, [idx]);

  const mode = useStageScale();
  const beat = beats[idx];
  const toneClass = beat.tone ? "tone-" + beat.tone : "";

  // Share actions
  const handleShareLink = () => {
    const url = `${location.origin}${location.pathname}#${beat.id}`;
    if (navigator.clipboard) {
      navigator.clipboard.writeText(url).then(
        () => showToast("Link copied"),
        () => showToast("Copy failed")
      );
    } else {
      showToast(url);
    }
  };
  const handleShareImage = () => {
    // Production wires html2canvas or a server screenshot service.
    // For the prototype: signal the intent and persist the beat id.
    showToast("Saved a card for this finding");
  };

  // Direction class
  const directionClass = tweaks.direction === "notebook" ? "dir-notebook" : "dir-findings";
  const themeClass = `theme-${tweaks.theme}`;
  const densityClass = `density-${tweaks.density}`;
  const paletteClass = `palette-${tweaks.palette}`;
  const Direction = tweaks.direction === "notebook" ? NotebookBeat : FindingsBeat;

  return (
    <div className="viewer">
      {/* Top meta band (sits outside the stage so it reads as page chrome) */}
      <div className="viewer-meta">
        <div className="brand">
          <img src="assets/momentic-logo-mark.png" alt="Momentic" />
          <span>Momentic Story</span>
        </div>
        <div className="counter">{String(idx + 1).padStart(2, "0")} / {String(beats.length).padStart(2, "0")} · {story.meta.title}</div>
      </div>

      {/* Desktop side rail — chapter list with current beat highlighted */}
      <aside className="chapter-rail">
        <div className="rail-head">
          <div className="rail-eyebrow">{story.meta.author} · {story.meta.year}</div>
          <div className="rail-title">{story.meta.title}</div>
          <div className="rail-subtitle">{story.meta.subtitle}</div>
        </div>
        <ol className="rail-list">
          {beats.map((b, i) =>
          <li
            key={b.id}
            className={"rail-item " + (i === idx ? "active" : i < idx ? "done" : "")}
            onClick={() => go(i)}>
            
              <span className="rail-num">{String(i + 1).padStart(2, "0")}</span>
              <span className="rail-label">{b.eyebrow || b.title}</span>
            </li>
          )}
        </ol>
      </aside>

      <div
        className="stage-wrap"
        style={{ width: mode.w, height: mode.h, transform: `scale(${mode.scale})`, transformOrigin: mode.landscape ? "right center" : "center center" }}>
        
        <div className={`stage ${themeClass} ${densityClass} ${paletteClass} ${directionClass} ${toneClass} ${mode.landscape ? "landscape" : "portrait"}`}>
          {/* Progress segments */}
          <div className="progress" role="progressbar" aria-valuemin="0" aria-valuemax={beats.length} aria-valuenow={idx + 1}>
            {beats.map((b, i) =>
            <div
              key={b.id}
              className={"progress-seg " + (i < idx ? "done" : i === idx ? "active" : "")}
              style={i === idx ? { "--p": `${progress * 100}%` } : null}>
              
                <div className="fill" />
              </div>
            )}
          </div>

          {/* Stage logo — links back to the research hub, skipping the intro animation */}
          <a className="stage-logo" href="../?skip=1" onClick={(e) => e.stopPropagation()} title="Back to all reports">
            <img className="mark" src="assets/momentic-logo-mark.png" alt="Momentic" />
          </a>

          {/* Share button — copies a link to this beat */}
          <button className="share-btn" onClick={handleShareLink} title="Copy link to this beat" style={{ fontFamily: "Inter" }}>
            <svg width="11" height="11" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M3.5 8.5 L9 3 M4.8 3 L9 3 L9 7.2"/></svg>
            <span>Share</span>
          </button>

          {/* Stage counter — bottom-right of every beat */}
          <div className="stage-counter">{String(idx + 1).padStart(2, "0")} / {String(beats.length).padStart(2, "0")}</div>

          {/* Beat content — keyed so animations restart on change */}
          <Direction
            key={beat.id + "-" + tweaks.direction}
            beat={beat}
            mascotsEnabled={tweaks.mascots} />
          

          {/* Tap zones — narrow strips at left and right edges only,
                so the middle of the stage stays clickable for chips, sliders, CTAs */}
          <div className="tap-zones left" onClick={prev} title="Previous" />
          <div className="tap-zones right" onClick={next} title="Next" />
          {/* nav-hint chevrons replaced by explicit nav buttons in .play-row */}
          

          {/* Bottom playback row — prev chevron · play / speed · next chevron */}
          <div className="play-row">
            <button className="nav-btn nav-btn-prev" onClick={prev} aria-label="Previous beat" disabled={idx === 0}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
            </button>
            <button className="play-ctl" onClick={() => setPlaying((p) => !p)}>
              <span>{playing ? "❚❚" : "▶"}</span>
              <span>{playing ? "Pause" : "Auto-play"}</span>
            </button>
            <button className="speed-pill" onClick={cycleSpeed} title="Adjust playback speed">{speedMul.toFixed(1)}×</button>
            <button className="nav-btn nav-btn-next" onClick={next} aria-label="Next beat" disabled={idx === beats.length - 1}>
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
            </button>
          </div>

          {/* Toast */}
          <div className={"toast " + (toastMsg ? "visible" : "")}>{toastMsg}</div>
        </div>
      </div>
    </div>);

}

/* =========================================================
   App + Tweaks panel
   ========================================================= */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "direction": "findings",
  "theme": "cream",
  "density": "spacious",
  "palette": "full",
  "mascots": true,
  "autoplaySeconds": 6
} /*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  return (
    <>
      <StoryViewer tweaks={t} />
      <TweaksPanel title="Story tweaks">
        <TweakSection label="Concept direction" />
        <TweakRadio
          label="Layout"
          value={t.direction}
          options={["findings", "notebook"]}
          onChange={(v) => setTweak("direction", v)} />
        
        <TweakSection label="Composition" />
        <TweakRadio
          label="Density"
          value={t.density}
          options={["spacious", "regular", "dense"]}
          onChange={(v) => setTweak("density", v)} />
        
        <TweakRadio
          label="Background"
          value={t.theme}
          options={["paper", "cream", "dark"]}
          onChange={(v) => setTweak("theme", v)} />
        
        <TweakRadio
          label="Palette"
          value={t.palette}
          options={["monochrome", "full"]}
          onChange={(v) => setTweak("palette", v)} />
        
        <TweakSection label="Voice" />
        <TweakToggle
          label="Show mascots"
          value={t.mascots}
          onChange={(v) => setTweak("mascots", v)} />
        
        <TweakSlider
          label="Autoplay speed"
          value={t.autoplaySeconds}
          min={3} max={15} step={1} unit="s"
          onChange={(v) => setTweak("autoplaySeconds", v)} />
        
      </TweaksPanel>
    </>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);