/* CONSOLE LAB - shared core for the 5 Claude-Code console treatments.
   Babel script. Reads window.SD.consoleScript + abmp3-kit (Icon).
   Exports: usePinProgress, clamp, lerp, PixelCrab, ScrollConsole,
   ConsoleAgentBar, ConsoleRecordCard, LabContext, exposes to window. */
const { useState, useEffect, useRef, useCallback, useMemo } = React;

const clamp = (v, lo = 0, hi = 1) => Math.min(hi, Math.max(lo, v));
const lerp = (a, b, t) => a + (b - a) * t;
/* remap x in [a,b] -> [0,1], clamped */
const span = (x, a, b) => clamp((x - a) / (b - a));

/* ----------------------------------------------------------------
   usePinProgress - progress 0..1 across a tall pin track.
   The track is `position:relative; height:<tall>` with a sticky
   child. Progress = how far the sticky child has been scrolled
   through. rAF-throttled, scroll + resize + poll for capture frames.
   ---------------------------------------------------------------- */
function usePinProgress(ref) {
  const [p, setP] = useState(0);
  const raf = useRef(0);
  useEffect(() => {
    const measure = () => {
      const el = ref.current;
      if (!el) return;
      const rect = el.getBoundingClientRect();
      const vh = window.innerHeight || document.documentElement.clientHeight || 800;
      const total = el.offsetHeight - vh;
      const scrolled = clamp(-rect.top, 0, Math.max(total, 1));
      setP(total > 0 ? scrolled / total : 0);
    };
    const onScroll = () => {
      cancelAnimationFrame(raf.current);
      raf.current = requestAnimationFrame(measure);
    };
    measure();
    window.addEventListener("scroll", onScroll, { passive: true });
    window.addEventListener("resize", onScroll);
    const poll = setInterval(measure, 250);
    return () => {
      cancelAnimationFrame(raf.current);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      clearInterval(poll);
    };
  }, []);
  return p;
}

/* ----------------------------------------------------------------
   PixelCrab - the coral Claude-Code avatar, recreated as crisp SVG
   so it scales + dances. Built from a boolean cell grid (real
   transparency, no background needed). `dancing` adds the bob loop.
   ---------------------------------------------------------------- */
const CRAB_W = 14, CRAB_H = 11;
const crabCells = (() => {
  const g = Array.from({ length: CRAB_H }, () => Array(CRAB_W).fill(false));
  // body block
  for (let r = 1; r <= 6; r++) for (let c = 2; c <= 11; c++) g[r][c] = true;
  // eyes (punched out)
  for (let r = 2; r <= 3; r++) { g[r][4] = false; g[r][9] = false; }
  // side arms
  g[4][0] = g[4][1] = true;
  g[4][12] = g[4][13] = true;
  // legs
  for (let r = 7; r <= 8; r++) { g[r][3] = true; g[r][5] = true; g[r][8] = true; g[r][10] = true; }
  return g;
})();

function PixelCrab({ size = 120, color = "#D9785C", dancing = false, blink = true, style, className = "" }) {
  const u = 1; // unit per cell
  const rects = [];
  for (let r = 0; r < CRAB_H; r++) for (let c = 0; c < CRAB_W; c++) {
    if (crabCells[r][c]) rects.push(<rect key={r + "-" + c} x={c} y={r} width={u + 0.04} height={u + 0.04} fill={color} />);
  }
  return (
    <svg
      className={"cl-crab" + (dancing ? " cl-crab--dance" : "") + (blink ? " cl-crab--blink" : "") + (className ? " " + className : "")}
      width={size} height={(size / CRAB_W) * CRAB_H}
      viewBox={`0 0 ${CRAB_W} ${CRAB_H}`} shapeRendering="crispEdges"
      style={style} aria-label="Claude Code"
    >
      {rects}
    </svg>
  );
}

/* ----------------------------------------------------------------
   Console line renderer - reuses .sd-cl markup from scroll.css so
   the typography matches the rest of the site. Reveals `shown`
   lines from window.SD.consoleScript. Stable: never un-reveals.
   ---------------------------------------------------------------- */
const GUT = { claude: "$", cmd: "›", info: "·", src: "↘", run: "•", ok: "✓", signal: "◆", done: "★" };

function ConsoleLines({ shown, streaming }) {
  const script = window.SD.consoleScript;
  const lines = script.slice(0, shown);
  return (
    <React.Fragment>
      {lines.map((l, i) => (
        <div key={i} className={"sd-cl sd-cl--" + l.t + " show"}>
          <span className="gut">{GUT[l.t] || "·"}</span>
          <div className="body">
            <span className="tx">{l.text}</span>
            {l.sub && l.t === "src"
              ? <div className="sd-cl-chips">{l.sub.split(" · ").map((c, j) => <span key={j} className="sd-cl-chip">{c}</span>)}</div>
              : l.sub && <div className="sub">{l.sub}</div>}
          </div>
        </div>
      ))}
      {streaming && shown > 0 && (
        <div className="sd-cl show" style={{ paddingLeft: 28 }}><span className="sd-caret" /></div>
      )}
    </React.Fragment>
  );
}

/* Keep the latest line in view as the body fills. */
function useStickBottom(ref, dep) {
  useEffect(() => { if (ref.current) ref.current.scrollTop = ref.current.scrollHeight; }, [dep]);
}

/* Agent orchestration bar (avatar + the three sub-agent chips). */
function ConsoleAgentBar({ group, done, crabSize = 30 }) {
  const agents = [["enrich", "Enrich"], ["research", "Research"], ["signal", "Signals"]];
  return (
    <div className="sd-agentbar">
      <PixelCrab size={crabSize} color={done ? "#4ED6A5" : "#D9785C"} dancing={!done} blink={!done} />
      <div style={{ minWidth: 0 }}>
        <div className="sd-agentbar-ttl">Claude Code agent {done ? "· run complete" : "· orchestrating"}</div>
        <div className="sd-agentchips">
          {agents.map(([k, l]) => (
            <span key={k} className={"sd-agentchip" + (group === k ? " on" : "") + (done ? " done" : "")}>{l}</span>
          ))}
        </div>
      </div>
      <span className="sd-agentarrow">→</span>
    </div>
  );
}

/* Final record card (same content as the live site). */
function ConsoleRecordCard() {
  const sigs = window.SD.signals;
  return (
    <div className="sd-record">
      <div className="sd-record-hd"><span className="mk">★</span> RECORD SENT TO CLAY</div>
      <div className="sd-record-row"><span className="k">account</span><span className="v">Northwind Logistics</span></div>
      <div className="sd-record-row"><span className="k">classified</span><span className="v">Tier 1 · fit 94 · intent HIGH · angle cost-to-serve</span></div>
      <div className="sd-record-row"><span className="k">signals enriched</span><span className="v">{sigs.length} tracked</span></div>
      <div className="sd-record-chips">{sigs.map((s) => <span key={s} className="sd-record-chip">{s}</span>)}</div>
    </div>
  );
}

/* ----------------------------------------------------------------
   ScrollConsole - the dark console panel, body reveal driven by a
   0..1 `progress` value. agentBar optional, record card on done.
   Shows a caret while streaming. Used by several options.
   ---------------------------------------------------------------- */
function ScrollConsole({ progress, title = "claude-code · research agent", height, agentBar = true, recordCard = true, headChrome = true }) {
  const script = window.SD.consoleScript;
  const N = script.length;
  const shown = Math.round(clamp(progress) * N);
  const done = shown >= N;
  const group = shown > 0 ? (script[Math.min(shown, N) - 1] || {}).group : null;
  const bodyRef = useRef(null);
  useStickBottom(bodyRef, shown);
  return (
    <div className="sd-console cl-console" style={{ height }}>
      {headChrome && (
        <div className="sd-console-bar">
          <span className="lights"><i style={{ background: "#ff5f57" }} /><i style={{ background: "#febc2e" }} /><i style={{ background: "#28c840" }} /></span>
          <span className="ttl">{title}</span>
          <span className="live"><i />{done ? "READY" : "STREAMING"}</span>
        </div>
      )}
      <div className="sd-console-body" ref={bodyRef} style={{ height: headChrome ? "calc(100% - 45px)" : "100%" }}>
        {agentBar && <ConsoleAgentBar group={group} done={done} />}
        <ConsoleLines shown={shown} streaming={!done} />
        {done && recordCard && <ConsoleRecordCard />}
      </div>
    </div>
  );
}

/* Small reusable framing band shown above/below an option so the
   pin + release reads in context (slim slices of §01 and §03). */
function LabBandTop() {
  return (
    <div className="cl-band cl-band--top">
      <div className="cl-wrap">
        <div className="cl-kick"><span className="bar" />01 / 04 · SOURCING & TAM BUILD</div>
        <h3>A dozen sources, engineered into one database.</h3>
        <p>Twelve feeds matched, deduplicated and filtered to ICP - then handed to the agent below.</p>
        <div className="cl-scrollcue"><span className="dot" /> SCROLL · WATCH IT BUILD</div>
      </div>
    </div>
  );
}
function LabBandBottom() {
  return (
    <div className="cl-band cl-band--bottom">
      <div className="cl-wrap">
        <div className="cl-kick"><span className="bar" />03 / 04 · CLASSIFY · ROUTE · ACTIVATE</div>
        <h3>One sales table routes the whole motion.</h3>
        <p>Every enriched account lands in the team's table - classified, tiered and wired to its next action.</p>
      </div>
    </div>
  );
}

/* Section heading used inside each option. */
function LabHead() {
  return (
    <div className="cl-wrap cl-sechead">
      <div className="cl-kick cl-kick--center"><span className="bar" />02 / 04 · ENRICHMENT, RESEARCH & SIGNALS</div>
      <h2>Claude turns each account into intelligence.</h2>
      <p>A Claude Code agent enriches from 10 sources, researches the company across the web, and tracks every buying signal - then writes the record to the sales table.</p>
    </div>
  );
}

Object.assign(window, {
  clamp, lerp, span, usePinProgress, PixelCrab,
  ConsoleLines, ConsoleAgentBar, ConsoleRecordCard, ScrollConsole,
  useStickBottom, LabBandTop, LabBandBottom, LabHead,
});
