/* EYE A — "From a repo": the live hero of the web app */

const EXAMPLES = {
  ramen: {
    label: "enderh3art/Ramen-Shop",
    repo: "github.com/enderh3art/Ramen-Shop",
    title: "RAMEN.SHOP",
    accent: "#E8893B",
    model: "sphere",
    stats: "1 mesh · 3 materials · 2 text nodes",
    script: [
      { arrow: "→", text: "fetching repository ", em: "enderh3art/Ramen-Shop" },
      { arrow: "→", text: "resolving build · ", wire: "three.js r158 + vite" },
      { arrow: "→", text: "parsing scene graph: ", em: "1 mesh, 3 materials, 2 text nodes" },
      { arrow: "→", text: "tracing data flow → uniforms, props, GLSL constants" },
      { arrow: "→", text: "identifying editable parameters…" },
      { arrow: "→", text: "exposing ", wire: "hero_text, accent_color, model", done: true },
    ],
  },
  folio: {
    label: "vael/neon-folio",
    repo: "github.com/vael/neon-folio",
    title: "NIGHT-OWL",
    accent: "#5BA8D4",
    model: "torus",
    stats: "2 meshes · post-fx · 1 text node",
    script: [
      { arrow: "→", text: "fetching repository ", em: "vael/neon-folio" },
      { arrow: "→", text: "resolving build · ", wire: "react-three-fiber + bloom" },
      { arrow: "→", text: "parsing scene graph: ", em: "2 meshes, post-fx, 1 text node" },
      { arrow: "→", text: "isolating bloom + emissive uniforms" },
      { arrow: "→", text: "identifying editable parameters…" },
      { arrow: "→", text: "exposing ", wire: "hero_text, accent_color, model", done: true },
    ],
  },
  grid: {
    label: "mono/brutal-grid",
    repo: "github.com/mono/brutal-grid",
    title: "GRID//SYS",
    accent: "#5BC48E",
    model: "cube",
    stats: "instanced mesh · 1 material",
    script: [
      { arrow: "→", text: "fetching repository ", em: "mono/brutal-grid" },
      { arrow: "→", text: "resolving build · ", wire: "webgl + glsl" },
      { arrow: "→", text: "parsing scene graph: ", em: "instanced mesh, 1 material" },
      { arrow: "→", text: "reading instance transforms + grid density" },
      { arrow: "→", text: "identifying editable parameters…" },
      { arrow: "→", text: "exposing ", wire: "hero_text, accent_color, model", done: true },
    ],
  },
};

const ACCENTS = ["#E8893B", "#5BA8D4", "#5BC48E", "#D46FA8", "#ECEEF1"];
const MODELS = [
  { id: "sphere", label: "ramen_bowl" },
  { id: "torus", label: "halo_ring" },
  { id: "cube", label: "logo_block" },
];

// LIVE MODE (opt-in): open the site with ?live to stream the REAL agent's reasoning into the
// feed instead of the recorded script. ?sse=<url> (or window.GRAIN_AGENT_SSE) points at the
// agent's SSE endpoint (agent/src/stream.ts, default :8770/events). If the agent isn't reachable
// it falls back to the recorded reconstruction — so the public site is always safe.
const LIVE_Q = new URLSearchParams(location.search);
const LIVE_MODE = LIVE_Q.has("live");
const AGENT_SSE = LIVE_Q.get("sse") || window.GRAIN_AGENT_SSE || "http://localhost:8770/events";

function EyeA() {
  const [ref, shown] = useReveal();
  const [exKey, setExKey] = React.useState("ramen");
  const ex = EXAMPLES[exKey];

  const [stage, setStage] = React.useState("idle"); // idle | reconstructing | done
  const [params, setParams] = React.useState({ title: ex.title, accent: ex.accent, model: ex.model });
  const [active, setActive] = React.useState(null); // which param is being touched
  const { lines, running, run, clear, begin, push, end } = useStream();
  const feedRef = React.useRef(null);
  const closeRef = React.useRef(null);                                  // active agent SSE subscription
  const [liveState, setLiveState] = React.useState(LIVE_MODE ? "ready" : "off");

  React.useEffect(() => {
    if (feedRef.current) feedRef.current.scrollTop = feedRef.current.scrollHeight;
  }, [lines]);
  React.useEffect(() => () => { closeRef.current && closeRef.current(); }, []); // close stream on unmount

  const pickExample = (k) => {
    setExKey(k);
    const e = EXAMPLES[k];
    setStage("idle"); clear();
    setParams({ title: e.title, accent: e.accent, model: e.model });
  };

  const reconstruct = () => {
    if (LIVE_MODE) return reconstructLive();
    setStage("reconstructing");
    setParams({ title: ex.title, accent: ex.accent, model: ex.model });
    run(ex.script, () => setStage("done"));
  };

  // map one agent SSE event onto a feed line (same shape the recorded demo uses)
  const mapAgentEvent = (ev) => {
    switch (ev.stage) {
      case "run":      begin(); setStage("reconstructing"); push({ arrow: "●", text: "agent run · ", em: ev.label || "reconstruct" }); break;
      case "think":    if (ev.text) push({ arrow: "→", text: ev.text }); break;
      case "act":      push({ arrow: "→", text: "", em: ev.tool, wire: " " + shortVal(ev.args) }); break;
      case "result":   push({ arrow: ev.ok ? "✓" : "✗", text: "", em: ev.tool, wire: " " + shortVal(ev.detail) }); break;
      case "approval": push({ arrow: "⏸", text: "human approval — ", wire: shortVal(ev.args) }); break;
      case "gate":     push({ arrow: ev.ok ? "✓" : "✗", text: (ev.ok ? "approved" : "denied") + (ev.reason ? " — " + ev.reason : "") }); break;
      case "final":    push({ arrow: "→", text: ev.text || "reconstruction complete", done: true }); end(); setStage("done"); break;
      default: break;
    }
  };

  // attach to the running agent's live reasoning; fall back to the recorded demo if unreachable
  const reconstructLive = () => {
    closeRef.current && closeRef.current();
    setStage("reconstructing"); setLiveState("connecting"); begin();
    push({ arrow: "→", text: "attaching to live agent · ", wire: AGENT_SSE });
    closeRef.current = subscribeAgent(AGENT_SSE, {
      onEvent: (ev) => { setLiveState("live"); mapAgentEvent(ev); },
      onError: () => {
        setLiveState("offline");
        push({ arrow: "✗", text: "agent unreachable — ", wire: "showing recorded reconstruction" });
        setParams({ title: ex.title, accent: ex.accent, model: ex.model });
        run(ex.script, () => setStage("done"));
      },
    });
  };

  const setP = (k, v) => setParams(p => ({ ...p, [k]: v }));

  return (
    <section className="section" id="eye-a" ref={ref}>
      <div className="wrap">
        <SectionHead idx="EYE A — 01" kind="READ" title="From a repo" sub="Open source in, editable scene out. Point Grain at a repository and watch it reconstruct the running visual as parameters you can drive — live, in this browser." shown={shown} motif="assets/eye-a-read.png" accent="var(--grain)" />

        <div className={`panel eyea-panel ${shown ? "in" : ""}`} style={{ marginTop: 56 }}>
          <div className="panel-head">
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <span className="panel-dots"><i></i><i></i><i></i></span>
              <span className="panel-title">grain · reconstruct.repo</span>
            </div>
            <span className="panel-title" style={{ color: stage === "done" || liveState === "live" ? "var(--grain)" : "var(--text-faint)" }}>
              {LIVE_MODE
                ? (liveState === "live" ? "● LIVE — agent" : liveState === "connecting" ? "CONNECTING…" : liveState === "offline" ? "OFFLINE — recorded" : "LIVE MODE")
                : (stage === "idle" ? "READY" : stage === "reconstructing" ? "RECONSTRUCTING…" : "● LIVE")}
            </span>
          </div>

          <div className="editor-tabs">
            <span className="editor-tab on"><span className="tdot" />reconstruct.repo</span>
            <span className="editor-tab muted"><span className="tdot" />scene.glb</span>
            <span className="editor-tab muted"><span className="tdot" />params.json</span>
          </div>

          <div className="eyea-grid">
            {/* LEFT — input + reasoning */}
            <div className="eyea-left">
              <label className="param-label" style={{ display: "block", marginBottom: 9, color: "var(--text-faint)" }}>// source repository</label>
              <div className="field" style={{ marginBottom: 12 }}>
                <span className="prefix">git:</span>
                <input value={ex.repo} readOnly spellCheck={false} />
              </div>
              <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 16 }}>
                {Object.entries(EXAMPLES).map(([k, e]) => (
                  <button key={k} className={`chip ${k === exKey ? "active" : ""}`} onClick={() => pickExample(k)}>
                    <span className="dot" /> {e.label}
                  </button>
                ))}
              </div>
              <div style={{ display: "flex", gap: 12, alignItems: "center", marginBottom: 18 }}>
                <button className="btn btn-grain" onClick={reconstruct} disabled={running}>
                  {running ? (LIVE_MODE ? "Watching agent…" : "Reconstructing…") : stage === "done" ? (LIVE_MODE ? "Reattach" : "Reconstruct again") : (LIVE_MODE ? "Attach to live agent" : "Reconstruct")}
                  {!running && <span style={{ fontSize: 15 }}>↻</span>}
                </button>
                <span className="mono faint" style={{ fontSize: 11.5 }}>paste your own <span style={{ opacity: 0.6 }}>(beta)</span></span>
              </div>

              <div className="feed eyea-feed" ref={feedRef}>
                {lines.length === 0 && stage === "idle" && (
                  <div className="faint" style={{ opacity: 0.7 }}>// agent idle — press <span className="mono" style={{ color: "var(--grain)" }}>{LIVE_MODE ? "Attach to live agent" : "Reconstruct"}</span> to begin trace</div>
                )}
                {lines.map((ln, i) => (
                  <div key={i} className={`feed-line ${ln.done ? "done" : ""}`}>
                    <span className="arrow">{ln.arrow}</span>
                    <span className="body">{ln.text}{ln.em && <span className="em">{ln.em}</span>}{ln.wire && <span className="wire">{ln.wire}</span>}</span>
                  </div>
                ))}
                {(running || (stage === "done")) && (
                  <div className="feed-line" style={{ animation: "none", opacity: 1 }}>
                    <span className="arrow" style={{ color: "var(--text-faint)" }}>{stage === "done" ? "✓" : ""}</span>
                    <span className="body">{stage === "done" ? <span className="faint">trace complete · scene is live →</span> : <span className="feed-cursor" />}</span>
                  </div>
                )}
              </div>
            </div>

            {/* RIGHT — reconstruction + sliders */}
            <div className="eyea-right">
              <Viewport stage={stage} params={params} active={active} stats={ex.stats} />

              <div className="param-block" style={{ opacity: stage === "done" ? 1 : 0.4, pointerEvents: stage === "done" ? "auto" : "none", transition: "opacity 0.5s ease" }}>
                <div className="param">
                  <span className="param-label"><span className="sig">str </span>hero_text</span>
                  <div className="text-param">
                    <input value={params.title} onChange={e => setP("title", e.target.value)}
                      onFocus={() => setActive("title")} onBlur={() => setActive(null)} maxLength={16} spellCheck={false} />
                  </div>
                </div>

                <div className="param">
                  <span className="param-label"><span className="sig">hex </span>accent_color</span>
                  <div className="swatches" onMouseEnter={() => setActive("accent")} onMouseLeave={() => setActive(null)}>
                    {ACCENTS.map(c => (
                      <button key={c} className={`swatch ${params.accent === c ? "active" : ""}`} style={{ background: c }}
                        onClick={() => setP("accent", c)} aria-label={c} />
                    ))}
                    <span className="param-val" style={{ color: params.accent }}>{params.accent.toUpperCase()}</span>
                  </div>
                </div>

                <div className="param">
                  <span className="param-label"><span className="sig">enum </span>model</span>
                  <div className="segmented" onMouseEnter={() => setActive("model")} onMouseLeave={() => setActive(null)}>
                    {MODELS.map(m => (
                      <button key={m.id} className={params.model === m.id ? "on" : ""} onClick={() => setP("model", m.id)}>{m.label}</button>
                    ))}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
        <p className="mono faint" style={{ fontSize: 12, marginTop: 16, textAlign: "center" }}>
          Drag a value — the reconstructed scene updates in place. <span style={{ color: "var(--text-soft)" }}>That tactile loop is the whole product.</span>
        </p>
      </div>
    </section>
  );
}

function Viewport({ stage, params, active, stats }) {
  const assembling = stage === "reconstructing";
  const solid = stage === "done";
  return (
    <div className="viewport eyea-vp">
      <div className="vp-grid" />
      <span className="vp-tick tl" /><span className="vp-tick tr" /><span className="vp-tick bl" /><span className="vp-tick br" />
      <div className="vp-label">
        {solid ? <span className="live-dot" style={{ position: "relative", display: "inline-block" }} /> : <span style={{ width: 7, height: 7, borderRadius: "50%", background: "var(--text-faint)", display: "inline-block" }} />}
        {stage === "idle" ? "AWAITING INPUT" : assembling ? "ASSEMBLING…" : "RECONSTRUCTED"}
      </div>
      <span className="mono" style={{ position: "absolute", top: 12, right: 14, zIndex: 5, fontSize: 10, color: "var(--text-faint)", letterSpacing: "0.1em" }}>scene.glb</span>

      {/* the reconstructed scene */}
      <div style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center" }}>
        {stage === "idle" ? (
          <div className="mono faint" style={{ fontSize: 12, textAlign: "center", lineHeight: 2, opacity: 0.6 }}>
            ▢ no scene<br /><span style={{ fontSize: 10 }}>run a reconstruction to populate the viewport</span>
          </div>
        ) : (
          <div style={{ display: "grid", placeItems: "center", position: "relative", width: "100%", height: "100%", "--mc": params.accent }}>
            <div className="vp-objglow" />
            {params.model === "sphere" && <div className="vp-core" />}
            <div className="vp-floor" />
            <div style={{ position: "relative", transition: "transform 0.7s var(--spring)", transform: solid ? "scale(1)" : "scale(0.82)" }}>
              <ParamBox active={active === "model"} label="model" style={{ padding: 6 }}>
                <div className="vp-wire" style={{ "--mc": params.accent }}>
                  <Wireframe shape={params.model} color={params.accent} size={188} assembling={assembling} />
                </div>
              </ParamBox>
            </div>

            {/* title node */}
            <div style={{ position: "absolute", bottom: "13%", left: 0, right: 0, display: "grid", placeItems: "center", opacity: solid ? 1 : 0, transform: solid ? "translateY(0)" : "translateY(12px)", transition: "transform 0.6s var(--spring) 0.15s" }}>
              <ParamBox active={active === "title"} label="hero_text">
                <div style={{ fontFamily: "var(--font-display)", fontWeight: 600, fontSize: 30, letterSpacing: "-0.04em", color: "var(--text)", textShadow: `0 0 24px ${params.accent}55`, padding: "2px 8px" }}>
                  {params.title || "—"}
                </div>
              </ParamBox>
              <div style={{ height: 2, width: 60, background: params.accent, marginTop: 6, borderRadius: 2, boxShadow: `0 0 12px ${params.accent}`, transition: "background 0.3s, box-shadow 0.3s" }} className={active === "accent" ? "pulse-accent" : ""} />
            </div>
          </div>
        )}
      </div>

      {/* footer meta */}
      <div style={{ position: "absolute", bottom: 10, left: 12, right: 12, zIndex: 5, display: "flex", justifyContent: "space-between" }}>
        <span className="mono" style={{ fontSize: 9.5, color: "var(--text-faint)", letterSpacing: "0.08em" }}>{solid ? stats : "—"}</span>
        <span className="mono" style={{ fontSize: 9.5, color: "var(--text-faint)", letterSpacing: "0.08em" }}>{solid ? "60 fps · parametric" : ""}</span>
      </div>
    </div>
  );
}

function ParamBox({ active, label, children, style }) {
  return (
    <div style={{ position: "relative", borderRadius: 8, transition: "all 0.3s var(--ease)", outline: active ? "1px dashed var(--grain)" : "1px dashed transparent", outlineOffset: 4, ...style }}>
      {active && (
        <span className="mono" style={{ position: "absolute", top: -9, left: 6, fontSize: 9, color: "var(--grain-bright)", background: "var(--bg)", padding: "0 5px", letterSpacing: "0.1em", borderRadius: 3, zIndex: 6 }}>{label}</span>
      )}
      {children}
    </div>
  );
}

function SectionHead({ idx, kind, title, sub, shown, motif, accent = "var(--grain)" }) {
  return (
    <div className={`sec-head ${shown ? "in" : ""}`}>
      <div className="sec-head-row">
        <div className="sec-head-text">
          <div className="eyebrow" style={{ marginBottom: 22 }}>
            <span className="idx">{idx}</span>
            <span style={{ width: 28, height: 1, background: "var(--hairline)" }} />
            <span style={{ color: accent }}>{kind}</span>
          </div>
          <h2 className="h2" style={{ marginBottom: 22 }}>{title}</h2>
          <p className="lead">{sub}</p>
        </div>
        {motif && (
          <div className="sec-motif" style={{ backgroundImage: `url("${motif}")`, "--accent": accent }} aria-hidden="true">
            <span className="sec-motif-ring" />
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, { EyeA, Viewport, ParamBox, SectionHead });
