/* global React, useInView, Check */
const { useState: useStateIde, useEffect: useEffectIde, useRef: useRefIde } = React;

/* ---- tiny Python syntax highlighter -> React spans ---- */
const PY_KW = /^(import|from|as|def|return|for|in|if|else|elif|with|class|lambda|None|True|False|and|or|not|await|async|yield)$/;
function hlPython(line, keyPrefix) {
  // tokenize: comments, strings, decorators, the rest
  const out = [];
  let rest = line;
  let k = 0;
  // leading comment?
  const cmt = rest.indexOf("#");
  let codePart = rest, comment = "";
  if (cmt >= 0) { codePart = rest.slice(0, cmt); comment = rest.slice(cmt); }
  // split codePart by string literals first
  const re = /("[^"]*"|'[^']*')/g;
  let last = 0, m;
  const pushCode = (txt) => {
    // split into words / symbols
    txt.split(/(\b)/).forEach((tok) => {
      if (!tok) return;
      if (PY_KW.test(tok)) out.push(<span key={keyPrefix + "-" + (k++)} className="t-kw">{tok}</span>);
      else if (/^\d+(\.\d+)?$/.test(tok)) out.push(<span key={keyPrefix + "-" + (k++)} className="t-num">{tok}</span>);
      else out.push(<span key={keyPrefix + "-" + (k++)}>{tok}</span>);
    });
  };
  while ((m = re.exec(codePart))) {
    if (m.index > last) pushCode(codePart.slice(last, m.index));
    out.push(<span key={keyPrefix + "-s" + (k++)} className="t-str">{m[0]}</span>);
    last = m.index + m[0].length;
  }
  if (last < codePart.length) pushCode(codePart.slice(last));
  if (comment) out.push(<span key={keyPrefix + "-c"} className="t-cmt">{comment}</span>);
  // decorators
  if (line.trim().startsWith("@")) return [<span key={keyPrefix + "-d"} className="t-dec">{line}</span>];
  return out;
}

const CODE = [
  "import pystack as ps",
  "from pystack import analog, sky130",
  "",
  "@ps.agent.design",
  "def miller_ota(gbw='30MHz', pm='60deg'):",
  "    pdk = sky130.open()",
  "    ota = analog.two_stage_ota(pdk)",
  "    ota.spec(gbw=gbw, phase_margin=pm)",
  "    ota.size(method='gm_id')   # agent-tuned",
  "    ota.compensate(cc='auto')",
  "    return ota",
  "",
  "chip = miller_ota()",
  "chip.simulate('ac', cloud=True)",
  "chip.check(['drc', 'lvs'])",
];

/* ---- Bode plot (gain + phase) drawn as SVG, animates on view ---- */
function BodePlot() {
  const [ref, seen] = useInView(0.3);
  // gain: high-ish flat then -20dB/dec rolloff; phase drops
  const W = 360, H = 150, x0 = 34, y0 = 14, x1 = W - 8, y1 = H - 22;
  const fx = (i) => x0 + (i / 100) * (x1 - x0);
  const gainPts = [], phasePts = [];
  for (let i = 0; i <= 100; i++) {
    const f = i / 100;            // 0..1 in log-freq
    const gain = 60 - Math.max(0, (f - 0.18)) * 78;     // dB
    const g = Math.max(-6, gain);
    const gy = y0 + (1 - (g + 6) / 72) * (y1 - y0);
    gainPts.push([fx(i), gy]);
    const ph = -90 * (1 / (1 + Math.exp(-(f - 0.55) * 11))) - 28 * (1 / (1 + Math.exp(-(f - 0.85) * 14)));
    const py = y0 + (-ph / 180) * (y1 - y0);
    phasePts.push([fx(i), Math.min(y1, py)]);
  }
  const toPath = (pts) => "M" + pts.map((p) => p[0].toFixed(1) + "," + p[1].toFixed(1)).join(" L");
  return (
    <div className="bode" ref={ref}>
      <div className="bode__head mono">
        <span><i className="bode__sw bode__sw--g" /> |H(f)| dB</span>
        <span><i className="bode__sw bode__sw--p" /> phase</span>
        <span className="spacer" />
        <span className="bode__metric">GBW <b>32 MHz</b></span>
        <span className="bode__metric">PM <b>61&deg;</b></span>
      </div>
      <svg viewBox={`0 0 ${W} ${H}`} className={"bode__svg " + (seen ? "is-in" : "")}>
        {[0, 1, 2, 3].map((i) => (
          <line key={i} x1={x0} x2={x1} y1={y0 + (i / 3) * (y1 - y0)} y2={y0 + (i / 3) * (y1 - y0)} className="bode__grid" />
        ))}
        {["1Hz", "1kHz", "1MHz", "1GHz"].map((t, i) => (
          <text key={t} x={x0 + (i / 3) * (x1 - x0)} y={H - 7} className="bode__axis">{t}</text>
        ))}
        <path d={toPath(phasePts)} className="bode__line bode__line--p" pathLength="1" />
        <path d={toPath(gainPts)} className="bode__line bode__line--g" pathLength="1" />
      </svg>
    </div>
  );
}

/* ---- Agent chat ---- */
function AgentChat() {
  const [ref, seen] = useInView(0.4);
  const [stage, setStage] = useStateIde(0); // 0 thinking, 1 answered
  useEffectIde(() => {
    if (!seen) return;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    const t = setTimeout(() => setStage(1), reduce ? 0 : 1400);
    return () => clearTimeout(t);
  }, [seen]);
  return (
    <div className="chat" ref={ref}>
      <div className="chat__msg chat__msg--user">
        <span className="chat__role mono">you</span>
        <p>Design a 2-stage Miller OTA in SKY130. GBW &ge; 30&nbsp;MHz, PM &ge; 60&deg;, minimize input-referred noise.</p>
      </div>
      <div className="chat__msg chat__msg--agent">
        <span className="chat__role mono"><i className="chat__dot" />agent</span>
        {stage === 0 ? (
          <p className="chat__thinking"><i /><i /><i /> drafting topology &amp; sizing</p>
        ) : (
          <p>
            Drafted a two-stage Miller topology, sized with <code>gm/Id</code>, added auto compensation.
            Ran AC in the cloud &mdash; <b>GBW&nbsp;32&nbsp;MHz</b>, <b>PM&nbsp;61&deg;</b>. DRC/LVS clean.
            Want me to trade gain for power next?
          </p>
        )}
      </div>
    </div>
  );
}

function IdeSection() {
  return (
    <section className="section" id="ide">
      <div className="container">
        <div className="sec-head sec-head--center reveal">
          <Eyebrow>The portal</Eyebrow>
          <h2 className="h2">A Python-native IDE,<br />with an <em>engineer</em> beside you.</h2>
          <p className="lead sec-head__lead" style={{ marginInline: "auto" }}>
            Code-driven schematic capture and layout, versioned in Git. Prompt the agent in
            natural language; it writes and runs the Python &mdash; you stay in control of every line.
          </p>
        </div>

        <div className="ide window reveal" data-d="1">
          <div className="window__bar">
            <span className="window__dots"><i /><i /><i /></span>
            <span className="window__title">miller_ota.py &mdash; py-stack</span>
            <span className="spacer" />
            <span className="status-chip"><Check /> venv: sky130</span>
          </div>
          <div className="ide__grid">
            <aside className="ide__chat"><AgentChat /></aside>
            <div className="ide__editor">
              <pre className="code">
                {CODE.map((ln, i) => (
                  <div className="code__ln" key={i}>
                    <span className="code__num">{i + 1}</span>
                    <span className="code__txt">{ln ? hlPython(ln, "l" + i) : "\u00a0"}</span>
                  </div>
                ))}
              </pre>
              <div className="ide__out">
                <div className="ide__out-bar mono"><span className="status-chip"><span className="dot-run" /> ac sim {"\u00b7"} cloud</span> <span className="muted">streamed back in 2.41s</span></div>
                <BodePlot />
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}

Object.assign(window, { IdeSection, BodePlot, AgentChat, hlPython });
