/* projects.jsx — bento grid + tilt + nodeprompt mini graph */

const { useState: useStateP, useEffect: useEffectP, useRef: useRefP } = React;

function TiltCard({ children, style, intensity = 6, ...props }) {
  const ref = useRefP(null);
  const [tilt, setTilt] = useStateP({ rx: 0, ry: 0 });
  const hoverable = typeof window !== "undefined" && window.__hasHover;
  const onMove = (e) => {
    if (!window.__hasHover) return;
    const r = ref.current.getBoundingClientRect();
    const cx = (e.clientX - r.left) / r.width - 0.5;
    const cy = (e.clientY - r.top) / r.height - 0.5;
    setTilt({ rx: -cy * intensity, ry: cx * intensity });
  };
  const onLeave = () => setTilt({ rx: 0, ry: 0 });
  return (
    <div
      ref={ref}
      onMouseMove={onMove}
      onMouseLeave={onLeave}
      style={{
        ...style,
        boxSizing: "border-box",
        maxWidth: "100%",
        ...(hoverable
          ? {
              transform: `perspective(1200px) rotateX(${tilt.rx}deg) rotateY(${tilt.ry}deg)`,
              transition: "transform 400ms var(--easing-default)",
              transformStyle: "preserve-3d",
            }
          : {}),
      }}
      {...props}
    >
      {children}
    </div>
  );
}

function NodeGraphMini() {
  const ref = useRefP(null);
  useEffectP(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext("2d");
    let raf, t = 0;
    const resize = () => {
      const dpr = Math.min(window.devicePixelRatio || 1, 2);
      const r = c.getBoundingClientRect();
      c.width = r.width * dpr; c.height = r.height * dpr; ctx.scale(dpr, dpr);
    };
    resize();
    window.addEventListener("resize", resize);

    // 12 nodes in a soft circle + cross-edges
    const N = 14;
    const nodes = Array.from({ length: N }, (_, i) => ({
      a: (i / N) * Math.PI * 2,
      r: 0.32 + (i % 3) * 0.08,
      phase: Math.random() * Math.PI * 2,
    }));
    const edges = [];
    for (let i = 0; i < N; i++) {
      edges.push([i, (i + 1) % N]);
      if (i % 3 === 0) edges.push([i, (i + 5) % N]);
      if (i % 4 === 0) edges.push([i, (i + 7) % N]);
    }

    const tick = () => {
      t += 0.005;
      const r = c.getBoundingClientRect();
      ctx.clearRect(0, 0, r.width, r.height);
      const cx = r.width / 2, cy = r.height / 2;
      const radius = Math.min(r.width, r.height) * 0.42;

      const pts = nodes.map((n, i) => {
        const wobble = Math.sin(t + n.phase) * 0.06;
        const a = n.a + t * 0.15;
        return {
          x: cx + Math.cos(a) * radius * (n.r + wobble) * 1.4,
          y: cy + Math.sin(a) * radius * (n.r + wobble) * 1.4,
        };
      });

      ctx.strokeStyle = "rgba(10,10,10,0.4)";
      ctx.lineWidth = 0.8;
      edges.forEach(([a, b]) => {
        ctx.beginPath();
        ctx.moveTo(pts[a].x, pts[a].y);
        ctx.lineTo(pts[b].x, pts[b].y);
        ctx.stroke();
      });

      pts.forEach((p, i) => {
        ctx.fillStyle = i % 3 === 0 ? "var(--fg)" : "#fff";
        ctx.strokeStyle = "var(--fg)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc(p.x, p.y, 4, 0, Math.PI * 2);
        ctx.fill();
        ctx.stroke();
      });

      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => { cancelAnimationFrame(raf); window.removeEventListener("resize", resize); };
  }, []);
  return <canvas ref={ref} style={{ width: "100%", height: "100%" }} />;
}

function Projects() {
  useLang();
  const { go } = useRouter();
  return (
    <div className="page" style={{ paddingTop: 140 }}>
      <div className="page-eyebrow">
        <span className="micro">{t("Index")} 03</span>
        <span style={{ width: 24, height: 1, background: "var(--fg)" }} />
        <span className="micro micro-fg">{t("Projects · Built things")}</span>
      </div>

      <div className="responsive-stack" style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 64, marginBottom: 64, alignItems: "end" }}>
        <h1 className="display-xl">
          {t("Tools that take a hard idea and make it small enough to hold in one hand.")}
        </h1>
        <div style={{ display: "flex", flexDirection: "column", gap: 18 }}>
          {/* Zigzag node trace — variation: squares (built things), denser
              oscillation, terminal "card" node mirroring the bento tile shape */}
          <svg viewBox="0 0 600 96" preserveAspectRatio="none"
               style={{ width: "100%", height: 96, display: "block", overflow: "visible" }}>
            {/* Faint grid baseline to reinforce the "built / engineered" mood */}
            <line x1="0" y1="48" x2="600" y2="48"
                  stroke="var(--line-soft)" strokeWidth="1"
                  strokeDasharray="1 6" vectorEffect="non-scaling-stroke" />
            <polyline
              points="-10,18 60,72 130,28 200,76 270,24 340,70 410,30 480,66 540,40"
              fill="none"
              stroke="var(--fg)"
              strokeWidth="1"
              vectorEffect="non-scaling-stroke"
              strokeDasharray="3 3"
              strokeLinecap="square"
              strokeLinejoin="miter"
            />
            {/* Square node markers (vs. about page's circles) */}
            {[
              [60, 72], [130, 28], [200, 76], [270, 24], [340, 70], [410, 30], [480, 66],
            ].map(([cx, cy], i) => (
              <rect key={i} x={cx - 3} y={cy - 3} width="6" height="6"
                    fill="var(--bg)" stroke="var(--fg)" strokeWidth="1"
                    vectorEffect="non-scaling-stroke" />
            ))}
            {/* Origin tick — solid square at the column edge */}
            <rect x="-13" y="15" width="6" height="6" fill="var(--fg)" />
            {/* Terminal "card" node — square block that nods to a bento tile */}
            <g transform="translate(540, 40)">
              <rect x="-12" y="-12" width="24" height="24"
                    fill="rgba(14,14,16,0.95)" stroke="var(--fg)" strokeWidth="1"
                    vectorEffect="non-scaling-stroke" />
              <rect x="-16" y="-16" width="32" height="32"
                    fill="none" stroke="var(--line)" strokeWidth="1"
                    vectorEffect="non-scaling-stroke" />
            </g>
          </svg>
          <div className="body-lg" style={{ color: "var(--fg-muted)" }}>
            {t("A short list. The hero is NodePrompt — a Mark-Lombardi-coded canvas for thinking with LLMs in graphs instead of chats. Alongside it, Paideia: a Claude Code plugin that turns a course folder into a self-formatting study system, ported to OpenAI Codex CLI as a sibling edition.")}
          </div>
        </div>
      </div>

      {/* Bento grid */}
      <div className="bento-grid" style={{
        display: "grid",
        gridTemplateColumns: "repeat(6, 1fr)",
        gridAutoRows: "200px",
        gap: 16,
        marginBottom: 80,
      }}>
        {/* NodePrompt — hero */}
        <TiltCard
          onClick={() => go("nodeprompt")}
          data-cursor="link" data-cursor-label={t("View Project")}
          intensity={4}
          style={{
            gridColumn: "span 4", gridRow: "span 3",
            border: "1px solid var(--line)", background: "var(--bg)",
            position: "relative", overflow: "hidden", padding: 28,
            display: "flex", flexDirection: "column",
          }}>
          <div style={{ position: "absolute", inset: 0, opacity: 0.6 }}>
            <NodeGraphMini />
          </div>
          <div style={{ position: "relative", zIndex: 1, display: "flex", justifyContent: "space-between" }}>
            <span className="micro">{t("01 / Hero")}</span>
            <span className="micro">{t("2026 — present")}</span>
          </div>
          <div style={{ flex: 1 }} />
          <div style={{ position: "relative", zIndex: 1 }}>
            <div className="display-xl" style={{ marginBottom: 12, fontSize: "clamp(40px, 5vw, 72px)" }}>NodePrompt</div>
            <div className="body-lg" style={{ maxWidth: 520, color: "var(--fg-muted)", marginBottom: 16 }}>
              {t("A node-graph environment for LLM workflows. Mark Lombardi's diagrams, but the edges are prompts.")}
            </div>
            <div style={{ display: "flex", gap: 24, flexWrap: "wrap" }}>
              <span className="micro micro-fg">{t("↳ React Three Fiber")}</span>
              <span className="micro micro-fg">{t("↳ TypeScript")}</span>
              <span className="micro micro-fg">{t("↳ Live demo")}</span>
            </div>
          </div>
        </TiltCard>

        {/* Paideia — secondary case study */}
        <TiltCard
          onClick={() => go("paideia")}
          data-cursor="link" data-cursor-label={t("View Project")}
          style={{
            gridColumn: "span 2", gridRow: "span 2",
            border: "1px solid var(--line)", padding: 24,
            display: "flex", flexDirection: "column", justifyContent: "space-between",
            position: "relative", overflow: "hidden",
          }}>
          {/* tier-pattern backdrop hinting at the heatmap */}
          <svg viewBox="0 0 200 160" preserveAspectRatio="none"
               style={{ position: "absolute", inset: 0, width: "100%", height: "100%", opacity: 0.45, pointerEvents: "none" }}>
            <defs>
              <pattern id="pa-card-hatch" patternUnits="userSpaceOnUse" width="4" height="4" patternTransform="rotate(45)">
                <line x1="0" y1="0" x2="0" y2="4" stroke="var(--fg)" strokeWidth="0.6" />
              </pattern>
            </defs>
            {Array.from({ length: 24 }).map((_, k) => {
              const col = k % 6, row = Math.floor(k / 6);
              const tier = [0,1,2,3,1,2,2,3,0,1,2,3,1,2,3,2,0,1,2,2,3,1,0,2][k];
              const x = 14 + col * 30, y = 10 + row * 32, w = 22, h = 22;
              if (tier === 0) return <rect key={k} x={x} y={y} width={w} height={h} fill="none" stroke="var(--fg)" strokeWidth={0.6} strokeDasharray="2 2" />;
              if (tier === 1) return <rect key={k} x={x} y={y} width={w} height={h} fill="none" stroke="var(--fg)" strokeWidth={0.6} />;
              if (tier === 2) return <rect key={k} x={x} y={y} width={w} height={h} fill="url(#pa-card-hatch)" stroke="var(--fg)" strokeWidth={0.6} />;
              return <rect key={k} x={x} y={y} width={w} height={h} fill="var(--fg)" stroke="var(--fg)" strokeWidth={0.6} />;
            })}
          </svg>
          <div style={{ position: "relative", zIndex: 1 }}>
            <div className="micro" style={{ marginBottom: 8 }}>{t("02 · Plugin")}</div>
            <div className="display-md" style={{ fontSize: 32 }}>Paideia</div>
            <div className="micro" style={{ color: "var(--fg-muted)", marginTop: 4 }}>Παιδεία</div>
          </div>
          <div className="body-sm" style={{ color: "var(--fg-muted)", position: "relative", zIndex: 1, background: "var(--bg)" }}>
            {t("Claude Code plugin. Turns a course folder into a self-formatting study system. Six artifacts, one descending counter.")}
          </div>
          <div className="micro micro-fg" style={{ position: "relative", zIndex: 1 }}>{t("Claude Code · Markdown")}</div>
        </TiltCard>

        {/* Paideia · Codex edition — sibling port. Same on-disk study graph,
            re-homed onto OpenAI Codex CLI primitives ($paideia- verbs,
            AGENTS.md, paideia-mcp stdio MCP). Inverted card (dark on bg)
            so the two siblings read as a pair without being identical. */}
        <TiltCard
          onClick={() => go("paideia-codex")}
          data-cursor="link" data-cursor-label={t("View Project")}
          style={{
            gridColumn: "span 2", gridRow: "span 2",
            border: "1px solid var(--fg)", padding: 24,
            background: "var(--fg)", color: "var(--bg)",
            display: "flex", flexDirection: "column", justifyContent: "space-between",
            position: "relative", overflow: "hidden",
          }}>
          {/* stdio-bus motif — horizontal lanes hint at the bundled
              paideia-mcp stdio MCP server that replaces the Claude
              edition's per-PDF subagent fan-out. */}
          <svg viewBox="0 0 200 160" preserveAspectRatio="none"
               style={{ position: "absolute", inset: 0, width: "100%", height: "100%", opacity: 0.32, pointerEvents: "none" }}>
            <defs>
              <pattern id="pcx-card-bus" patternUnits="userSpaceOnUse" width="6" height="6">
                <line x1="0" y1="3" x2="6" y2="3" stroke="var(--bg)" strokeWidth="0.4" />
              </pattern>
            </defs>
            <rect x="0" y="0" width="200" height="160" fill="url(#pcx-card-bus)" />
            {[18, 42, 66, 90, 114, 138].map((y, i) => (
              <g key={i}>
                <line x1="14" y1={y} x2="186" y2={y} stroke="var(--bg)" strokeWidth="0.5" opacity="0.55" />
                {[28, 60, 92, 124, 156, 178].filter((_, k) => (k + i) % 2 === 0).map((x, j) => (
                  <rect key={j} x={x - 2} y={y - 2} width="4" height="4" fill="var(--bg)" opacity="0.7" />
                ))}
              </g>
            ))}
          </svg>
          <div style={{ position: "relative", zIndex: 1 }}>
            <div className="micro" style={{ marginBottom: 8, color: "rgba(255,255,255,0.6)" }}>{t("02b · Plugin · Codex edition")}</div>
            <div className="display-md" style={{ fontSize: 32, lineHeight: 1.05 }}>
              Paideia
              <span style={{ fontSize: 18, fontStyle: "italic", color: "rgba(255,255,255,0.62)", marginLeft: 8, fontFamily: "var(--font-display)" }}>· Codex</span>
            </div>
            <div className="micro" style={{ color: "rgba(255,255,255,0.55)", marginTop: 6, fontFamily: "var(--font-mono)", letterSpacing: "0.08em" }}>$paideia-* · OpenAI Codex CLI</div>
          </div>
          <div className="body-sm" style={{ color: "rgba(255,255,255,0.78)", position: "relative", zIndex: 1 }}>
            {t("OpenAI Codex CLI port. $paideia- verbs, AGENTS.md, bundled paideia-mcp stdio server. Same study graph, different runner.")}
          </div>
          <div className="micro" style={{ position: "relative", zIndex: 1, color: "rgba(255,255,255,0.7)" }}>{t("OpenAI Codex · MCP · Markdown")}</div>
        </TiltCard>

      </div>

      {/* NodePrompt detail strip */}
      <div className="four-col case-strip" style={{
        border: "1px solid var(--line)", padding: "clamp(20px, 4vw, 48px)", marginBottom: 80,
        display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr", gap: 32,
      }}>
        <div style={{ gridColumn: "span 4", marginBottom: 16 }}>
          <div className="micro" style={{ marginBottom: 12 }}>{t("Case study · NodePrompt")}</div>
          <div className="display-lg">{t("A canvas for thinking, not a chat for asking.")}</div>
        </div>
        <div>
          <div className="micro" style={{ marginBottom: 8 }}>{t("Problem")}</div>
          <div className="body-sm" style={{ color: "var(--fg-muted)" }}>{t("Linear chat hides the shape of an investigation.")}</div>
        </div>
        <div>
          <div className="micro" style={{ marginBottom: 8 }}>{t("Approach")}</div>
          <div className="body-sm" style={{ color: "var(--fg-muted)" }}>{t("Treat prompts as nodes; let edges encode dependency.")}</div>
        </div>
        <div>
          <div className="micro" style={{ marginBottom: 8 }}>{t("Result")}</div>
          <div className="body-sm" style={{ color: "var(--fg-muted)" }}>{t("Used internally for research planning and writing decomposition.")}</div>
        </div>
        <div>
          <div className="micro" style={{ marginBottom: 8 }}>{t("Stack")}</div>
          <div className="body-sm" style={{ color: "var(--fg-muted)" }}>{t("React Three Fiber, TypeScript, GSAP, Claude API.")}</div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { Projects, TiltCard, NodeGraphMini });
