/* Prerequisite graph view — hierarchical DAG, Vignelli-style */

const PrerequisiteGraph = ({ initialView = "hierarchical" } = {}) => {
  const [view, setView] = React.useState(initialView);
  const [hovered, setHovered] = React.useState(null);
  const [filterEdge, setFilterEdge] = React.useState({USES:true, DEFINES:true, PROVES:true, GENERALIZES:true, IS_EXAMPLE:true});

  // Hand-laid hierarchical layout — 8 ranks, columnar to a baseline grid.
  // x: column index 0..11 (12-col grid), y: rank 0..7 (top → bottom)
  const nodes = [
    // rank 0 — axioms / primitives
    { id:"real_numbers",  label:"Real numbers ℝ",   kind:"axiom",      mastery:"mastered", x:1, y:0 },
    { id:"set",           label:"Set",              kind:"definition", mastery:"mastered", x:4, y:0 },
    { id:"function",      label:"Function",         kind:"definition", mastery:"mastered", x:7, y:0 },
    { id:"interval",      label:"Open interval",    kind:"definition", mastery:"mastered", x:10,y:0 },

    // rank 1 — basic structures
    { id:"sequence",      label:"Sequence",         kind:"definition", mastery:"mastered", x:1, y:1 },
    { id:"slope_line",    label:"Slope of a line",  kind:"definition", mastery:"learning", x:3, y:1 },
    { id:"absolute_val",  label:"Absolute value",   kind:"definition", mastery:"mastered", x:5.5, y:1 },
    { id:"composition",   label:"Composition",      kind:"definition", mastery:"mastered", x:8, y:1 },

    // rank 2 — limits foundation
    { id:"limit_seq",     label:"Limit · sequence", kind:"definition", mastery:"mastered", x:1.5, y:2 },
    { id:"limit_func",    label:"Limit · function", kind:"definition", mastery:"mastered", x:5,   y:2 },
    { id:"epsilon_delta", label:"ε–δ definition",   kind:"definition", mastery:"learning", x:8.5, y:2 },

    // rank 3 — derived limit lemmas
    { id:"limit_sum",     label:"Limit · sum rule",     kind:"lemma",   mastery:"mastered", x:2,   y:3 },
    { id:"limit_product", label:"Limit · product rule", kind:"lemma",   mastery:"learning", x:5,   y:3 },
    { id:"limit_compose", label:"Limit · composition",  kind:"lemma",   mastery:"learning", x:8,   y:3 },

    // rank 4 — continuity + secants
    { id:"continuity",    label:"Continuity",       kind:"definition", mastery:"learning", x:3, y:4 },
    { id:"secant",        label:"Secant line",      kind:"definition", mastery:"frontier", x:6, y:4 },
    { id:"diff_quot",     label:"Difference quotient", kind:"definition", mastery:"frontier", x:9, y:4 },

    // rank 5 — DERIVATIVE node, central
    { id:"derivative",    label:"Derivative",       kind:"definition", mastery:"frontier", x:6, y:5, focus:true },

    // rank 6 — first-order theorems
    { id:"diff_implies_cont", label:"Differentiability ⇒ continuity", kind:"theorem", mastery:"mastered", x:1.5, y:6 },
    { id:"sum_rule",     label:"Sum rule (deriv.)", kind:"theorem", mastery:"mastered", x:4, y:6 },
    { id:"product_rule", label:"Product rule",      kind:"theorem", mastery:"learning", x:6.5, y:6 },
    { id:"chain_rule",   label:"Chain rule",        kind:"theorem", mastery:"frontier", x:9, y:6 },

    // rank 7 — downstream
    { id:"mvt",          label:"Mean value theorem", kind:"theorem", mastery:"locked", x:2, y:7 },
    { id:"l_hopital",    label:"L'Hôpital's rule",   kind:"theorem", mastery:"locked", x:5, y:7 },
    { id:"taylor",       label:"Taylor's theorem",   kind:"theorem", mastery:"locked", x:8, y:7 },
    { id:"newtons_method", label:"Newton's method",  kind:"procedure", mastery:"locked", x:10.5, y:7 },
  ];

  const edges = [
    // upstream into derivative
    {a:"function",     b:"derivative", t:"USES"},
    {a:"limit_func",   b:"derivative", t:"USES"},
    {a:"diff_quot",    b:"derivative", t:"DEFINES"},
    {a:"secant",       b:"derivative", t:"USES"},
    {a:"continuity",   b:"derivative", t:"USES"},
    {a:"interval",     b:"derivative", t:"USES"},

    // foundations
    {a:"real_numbers", b:"limit_seq",  t:"USES"},
    {a:"set",          b:"function",   t:"USES"},
    {a:"function",     b:"limit_func", t:"USES"},
    {a:"function",     b:"composition",t:"USES"},
    {a:"limit_seq",    b:"limit_func", t:"GENERALIZES"},
    {a:"limit_func",   b:"epsilon_delta", t:"DEFINES"},
    {a:"limit_func",   b:"limit_sum",  t:"USES"},
    {a:"limit_func",   b:"limit_product", t:"USES"},
    {a:"limit_func",   b:"limit_compose", t:"USES"},
    {a:"limit_func",   b:"continuity", t:"DEFINES"},
    {a:"slope_line",   b:"secant",     t:"USES"},
    {a:"slope_line",   b:"diff_quot",  t:"USES"},
    {a:"function",     b:"secant",     t:"USES"},
    {a:"absolute_val", b:"continuity", t:"USES"},

    // downstream from derivative
    {a:"derivative",   b:"diff_implies_cont", t:"PROVES"},
    {a:"derivative",   b:"sum_rule",   t:"PROVES"},
    {a:"derivative",   b:"product_rule", t:"PROVES"},
    {a:"derivative",   b:"chain_rule", t:"PROVES"},
    {a:"limit_sum",    b:"sum_rule",   t:"USES"},
    {a:"limit_product",b:"product_rule", t:"USES"},
    {a:"limit_compose",b:"chain_rule", t:"USES"},
    {a:"continuity",   b:"diff_implies_cont", t:"USES"},

    // far downstream
    {a:"diff_implies_cont", b:"mvt", t:"USES"},
    {a:"derivative",   b:"mvt",      t:"USES"},
    {a:"derivative",   b:"l_hopital",t:"USES"},
    {a:"derivative",   b:"taylor",   t:"USES"},
    {a:"derivative",   b:"newtons_method", t:"USES"},
  ];

  // grid: 12 columns wide, 8 ranks deep
  const COLS = 12, RANKS = 8;
  const W = 1100, H = 740;
  const PAD_X = 60, PAD_Y = 48;
  const xToPx = (x) => PAD_X + (x / (COLS - 1)) * (W - 2*PAD_X);
  const yToPx = (y) => PAD_Y + (y / (RANKS - 1)) * (H - 2*PAD_Y);

  const nodeById = Object.fromEntries(nodes.map(n => [n.id, n]));

  const isEdgeOn = (e) => {
    const map = { USES:"USES", DEFINES:"DEFINES", PROVES:"PROVES", GENERALIZES:"GENERALIZES", IS_EXAMPLE:"IS_EXAMPLE" };
    return filterEdge[map[e.t]];
  };

  const edgeColor = (t) => {
    if (t === "DEFINES") return "var(--accent)";
    if (t === "PROVES")  return "var(--ink)";
    if (t === "GENERALIZES") return "var(--ink-3)";
    return "var(--ink-3)";  // USES
  };
  const edgeDash = (t) => {
    if (t === "GENERALIZES") return "4 3";
    if (t === "DEFINES")     return undefined;
    if (t === "PROVES")      return undefined;
    return undefined;
  };

  return (
    <div className="pg">
      {/* top chrome */}
      <header className="pg__top">
        <div className="pg__top-l">
          <a className="cp__bc-link" href="#">← Derivative</a>
          <span className="cp__bc-sep">/</span>
          <span className="cp__bc-cur">Prerequisite graph</span>
        </div>
        <div className="pg__top-r">
          <span className="t-meta">View</span>
          <div className="pg__viewseg">
            <button className={"pg__viewseg-btn " + (view==="hierarchical"?"is-on":"")} onClick={()=>setView("hierarchical")}>Hierarchical</button>
            <button className={"pg__viewseg-btn " + (view==="force"?"is-on":"")} onClick={()=>setView("force")}>Force</button>
            <button className={"pg__viewseg-btn " + (view==="embedding"?"is-on":"")} onClick={()=>setView("embedding")}>Embedding</button>
          </div>
          <span className="cp__top-divider" />
          <button className="btn btn--ghost cp__top-btn">Reset</button>
          <button className="btn cp__top-btn">Focus on derivative</button>
        </div>
      </header>
      <hr className="rule" />

      <div className="pg__layout">
        {/* left rail — controls */}
        <aside className="pg__rail">
          <div className="pg__rail-block">
            <div className="t-meta pg__rail-h">Edge types</div>
            <hr className="rule-3" />
            <ul className="pg__edge-list">
              {[
                ["USES","Uses",       "var(--ink-3)", false],
                ["DEFINES","Defines", "var(--accent)", false],
                ["PROVES","Proves",   "var(--ink)",   false],
                ["GENERALIZES","Generalizes", "var(--ink-3)", true],
                ["IS_EXAMPLE","Is example of", "var(--ink-4)", true],
              ].map(([k, label, color, dashed]) => (
                <li key={k} className="pg__edge-item">
                  <input type="checkbox" id={"ef-"+k} checked={!!filterEdge[k]}
                         onChange={(e) => setFilterEdge({...filterEdge, [k]:e.target.checked})} />
                  <label htmlFor={"ef-"+k} className="pg__edge-lbl">
                    <svg width="24" height="8"><line x1="0" y1="4" x2="24" y2="4"
                      stroke={color} strokeWidth={k==="PROVES"?"2":"1.5"} strokeDasharray={dashed?"3 2":undefined} /></svg>
                    <span className="t-ui">{label}</span>
                  </label>
                </li>
              ))}
            </ul>
          </div>

          <div className="pg__rail-block">
            <div className="t-meta pg__rail-h">Node types</div>
            <hr className="rule-3" />
            <ul className="pg__nt-list">
              <li><span className="pg__nt pg__nt--axiom" /><span className="t-ui">Axiom</span><span className="t-mono pg__nt-n">04</span></li>
              <li><span className="pg__nt pg__nt--def" /><span className="t-ui">Definition</span><span className="t-mono pg__nt-n">14</span></li>
              <li><span className="pg__nt pg__nt--lemma" /><span className="t-ui">Lemma</span><span className="t-mono pg__nt-n">03</span></li>
              <li><span className="pg__nt pg__nt--theorem" /><span className="t-ui">Theorem</span><span className="t-mono pg__nt-n">07</span></li>
              <li><span className="pg__nt pg__nt--proc" /><span className="t-ui">Procedure</span><span className="t-mono pg__nt-n">02</span></li>
            </ul>
          </div>

          <div className="pg__rail-block">
            <div className="t-meta pg__rail-h">Mastery overlay</div>
            <hr className="rule-3" />
            <ul className="pg__nt-list">
              <li><span className="mastery-dot mastery-dot--mastered" /><span className="t-ui">Mastered</span><span className="t-mono pg__nt-n">11</span></li>
              <li><span className="mastery-dot mastery-dot--learning" /><span className="t-ui">Learning</span><span className="t-mono pg__nt-n">06</span></li>
              <li><span className="mastery-dot mastery-dot--frontier" /><span className="t-ui">Frontier</span><span className="t-mono pg__nt-n">04</span></li>
              <li><span className="mastery-dot mastery-dot--locked" /><span className="t-ui">Locked</span><span className="t-mono pg__nt-n">09</span></li>
            </ul>
          </div>

          <div className="pg__rail-block">
            <div className="t-meta pg__rail-h">Selected</div>
            <hr className="rule-3" />
            {hovered ? (
              <div className="pg__sel">
                <div className="t-h4 pg__sel-title">{nodeById[hovered].label}</div>
                <div className="t-mono pg__sel-id">{nodeById[hovered].kind}.{hovered}</div>
                <hr className="rule-3" style={{margin:"10px 0"}} />
                <div className="pg__sel-row"><span className="t-meta">In-degree</span><span className="t-mono">{edges.filter(e => e.b === hovered).length}</span></div>
                <div className="pg__sel-row"><span className="t-meta">Out-degree</span><span className="t-mono">{edges.filter(e => e.a === hovered).length}</span></div>
                <div className="pg__sel-row"><span className="t-meta">Mastery</span><span className="t-mono" style={{textTransform:"capitalize"}}>{nodeById[hovered].mastery}</span></div>
              </div>
            ) : (
              <div className="t-ui pg__sel-empty">Hover a node to inspect.<br/>Click to navigate.</div>
            )}
          </div>
        </aside>

        {/* graph stage */}
        <div className="pg__stage">
          {/* rank labels (Vignelli-style left gutter) — hierarchical only */}
          {view === "hierarchical" && (
            <div className="pg__ranks">
              {["Primitives","Structure","Limits","Limit lemmas","Continuity","Derivative","Theorems","Downstream"].map((r, i) => (
                <div key={i} className="pg__rank" style={{top: yToPx(i) + "px"}}>
                  <span className="t-mono pg__rank-n">R{i.toString().padStart(2,"0")}</span>
                  <span className="t-meta">{r}</span>
                </div>
              ))}
            </div>
          )}

          {view === "force" && <ForceLayout />}
          {view === "embedding" && <EmbeddingLayout />}
          {view === "hierarchical" && (
          <svg viewBox={`0 0 ${W} ${H}`} className="pg__svg" preserveAspectRatio="xMidYMid meet">
            {/* faint baseline grid */}
            {Array.from({length: RANKS}).map((_, i) => (
              <line key={i} x1={PAD_X} y1={yToPx(i)} x2={W-PAD_X} y2={yToPx(i)}
                    stroke="var(--rule-3)" strokeWidth="0.5" strokeDasharray="2 4" />
            ))}

            {/* edges first */}
            <g>
              {edges.filter(isEdgeOn).map((e, i) => {
                const a = nodeById[e.a], b = nodeById[e.b];
                if (!a || !b) return null;
                const ax = xToPx(a.x), ay = yToPx(a.y);
                const bx = xToPx(b.x), by = yToPx(b.y);
                // orthogonal Vignelli-style routing: vertical drop, then horizontal, then vertical
                const dy = by - ay;
                const midY = ay + dy * 0.5;
                const path = `M ${ax} ${ay+10} L ${ax} ${midY} L ${bx} ${midY} L ${bx} ${by-10}`;
                const isHovered = hovered && (e.a === hovered || e.b === hovered);
                return (
                  <path key={i} d={path}
                        fill="none"
                        stroke={isHovered ? "var(--accent)" : edgeColor(e.t)}
                        strokeWidth={e.t === "PROVES" ? 1.5 : 1}
                        strokeDasharray={edgeDash(e.t)}
                        opacity={hovered && !isHovered ? 0.15 : (e.t === "USES" ? 0.55 : 0.9)} />
                );
              })}
            </g>

            {/* nodes */}
            <g>
              {nodes.map((n) => {
                const cx = xToPx(n.x), cy = yToPx(n.y);
                const isHov = hovered === n.id;
                const dim = hovered && !isHov && !edges.some(e => (e.a===hovered && e.b===n.id) || (e.b===hovered && e.a===n.id));
                const fill = n.mastery === "mastered" ? "var(--ink)"
                          : n.mastery === "frontier" ? "var(--accent)"
                          : n.mastery === "learning" ? "var(--paper)"
                          : "var(--paper)";
                const stroke = n.mastery === "locked" ? "var(--rule-2)"
                            : n.mastery === "learning" ? "var(--ink)"
                            : n.mastery === "frontier" ? "var(--accent)"
                            : "var(--ink)";
                const tx = n.kind === "theorem" ? cx - 50 : cx - 50;
                const ty = cy - 22;
                return (
                  <g key={n.id} className="pg__node" opacity={dim ? 0.25 : 1}
                     onMouseEnter={() => setHovered(n.id)}
                     onMouseLeave={() => setHovered(null)}
                     style={{cursor:"pointer"}}>
                    {/* node mark */}
                    {n.kind === "theorem" || n.kind === "lemma" ? (
                      <rect x={cx-7} y={cy-7} width="14" height="14"
                            fill={fill} stroke={stroke} strokeWidth={n.focus ? 2 : 1.25} />
                    ) : n.kind === "axiom" ? (
                      <polygon points={`${cx},${cy-7} ${cx+7},${cy} ${cx},${cy+7} ${cx-7},${cy}`}
                               fill={fill} stroke={stroke} strokeWidth="1.25" />
                    ) : n.kind === "procedure" ? (
                      <polygon points={`${cx-7},${cy-5} ${cx+7},${cy-5} ${cx+5},${cy+5} ${cx-5},${cy+5}`}
                               fill={fill} stroke={stroke} strokeWidth="1.25" />
                    ) : (
                      <circle cx={cx} cy={cy} r={n.focus ? 8 : 6}
                              fill={fill} stroke={stroke} strokeWidth={n.focus ? 2 : 1.25} />
                    )}
                    {/* focus halo */}
                    {n.focus && (
                      <circle cx={cx} cy={cy} r="16" fill="none" stroke="var(--accent)" strokeWidth="1" strokeDasharray="2 2"/>
                    )}
                    {/* label — positioned consistently above-right */}
                    <text x={cx + 12} y={cy + 4}
                          fontFamily="var(--font-ui)" fontSize="11"
                          fontWeight={n.focus ? 600 : 500}
                          fill={n.mastery === "locked" ? "var(--ink-4)" : "var(--ink)"}>
                      {n.label}
                    </text>
                  </g>
                );
              })}
            </g>
          </svg>
          )}
        </div>
      </div>

      {/* bottom legend / status */}
      <hr className="rule-2" />
      <footer className="pg__foot">
        <span className="t-meta">28 nodes · 31 edges · subgraph of 'Calculus / Differentiation'</span>
        <span className="t-mono pg__foot-r">view: {view} · zoom 1.0× · materialized 2026-04-29</span>
      </footer>
    </div>
  );
};

window.PrerequisiteGraph = PrerequisiteGraph;
