/* Mastery map — the learner's relationship to the field
   Same graph substrate as PrerequisiteGraph but projected through learning state.
   FSRS retention is first-class. Domain-agnostic structure. */

const MasteryMap = () => {
  const [hovered, setHovered] = React.useState(null);
  const [filter, setFilter] = React.useState("all");

  // Same calculus subgraph as v1 but with FSRS retention state added.
  // mastery: mastered | review | learning | frontier | locked
  // retention: 0..1 (FSRS-projected probability of recall right now)
  // due: days until/since due (negative = overdue)
  const nodes = [
    // primitives — long mastered, high retention
    { id:"set",            label:"Set",                 kind:"definition", x:0.08, y:0.10, mastery:"mastered", retention:0.96, due: 18 },
    { id:"function",       label:"Function",            kind:"definition", x:0.20, y:0.08, mastery:"mastered", retention:0.94, due: 14 },
    { id:"real_numbers",   label:"Real numbers ℝ",      kind:"axiom",      x:0.32, y:0.14, mastery:"mastered", retention:0.91, due: 12 },
    { id:"interval",       label:"Open interval",       kind:"definition", x:0.44, y:0.06, mastery:"mastered", retention:0.88, due:  9 },
    { id:"absolute_val",   label:"Absolute value",      kind:"definition", x:0.55, y:0.13, mastery:"mastered", retention:0.93, due: 22 },
    { id:"composition",    label:"Composition",         kind:"definition", x:0.68, y:0.08, mastery:"mastered", retention:0.81, due:  4 },
    { id:"sequence",       label:"Sequence",            kind:"definition", x:0.80, y:0.14, mastery:"mastered", retention:0.62, due: -2 }, // overdue
    { id:"slope_line",     label:"Slope of a line",     kind:"definition", x:0.92, y:0.08, mastery:"mastered", retention:0.55, due: -5 }, // overdue → review
    // limits
    { id:"limit_seq",      label:"Limit · sequence",    kind:"definition", x:0.10, y:0.30, mastery:"mastered", retention:0.78, due:  2 },
    { id:"limit_func",     label:"Limit · function",    kind:"definition", x:0.30, y:0.28, mastery:"mastered", retention:0.71, due:  1 },
    { id:"epsilon_delta",  label:"ε–δ definition",      kind:"definition", x:0.48, y:0.34, mastery:"learning",retention:0.42, due:  0 },
    { id:"limit_sum",      label:"Limit · sum",         kind:"lemma",      x:0.66, y:0.28, mastery:"mastered", retention:0.84, due:  6 },
    { id:"limit_product",  label:"Limit · product",     kind:"lemma",      x:0.82, y:0.32, mastery:"learning",retention:0.51, due: -1 }, // review-due
    { id:"limit_compose",  label:"Limit · composition", kind:"lemma",      x:0.94, y:0.26, mastery:"learning",retention:0.46, due: -3 }, // review-due

    // continuity, secant, dq
    { id:"continuity",     label:"Continuity",          kind:"definition", x:0.18, y:0.48, mastery:"learning",retention:0.61, due:  0 },
    { id:"secant",         label:"Secant line",         kind:"definition", x:0.40, y:0.50, mastery:"frontier",retention:null, due:null },
    { id:"diff_quot",      label:"Difference quotient", kind:"definition", x:0.58, y:0.46, mastery:"frontier",retention:null, due:null },

    // DERIVATIVE — current frontier
    { id:"derivative",     label:"Derivative",          kind:"definition", x:0.50, y:0.62, mastery:"frontier", retention:null, due:null, focus:true },

    // first-order theorems
    { id:"diff_implies_cont", label:"Diff ⇒ continuity", kind:"theorem", x:0.16, y:0.74, mastery:"locked", retention:null, due:null },
    { id:"sum_rule",       label:"Sum rule",            kind:"theorem",    x:0.34, y:0.78, mastery:"locked", retention:null, due:null },
    { id:"product_rule",   label:"Product rule",        kind:"theorem",    x:0.56, y:0.80, mastery:"locked", retention:null, due:null },
    { id:"chain_rule",     label:"Chain rule",          kind:"theorem",    x:0.74, y:0.74, mastery:"locked", retention:null, due:null },

    // far downstream
    { id:"mvt",            label:"Mean value theorem",  kind:"theorem",    x:0.10, y:0.92, mastery:"locked", retention:null, due:null },
    { id:"l_hopital",      label:"L'Hôpital's rule",    kind:"theorem",    x:0.30, y:0.94, mastery:"locked", retention:null, due:null },
    { id:"taylor",         label:"Taylor's theorem",    kind:"theorem",    x:0.56, y:0.94, mastery:"locked", retention:null, due:null },
    { id:"newtons_method", label:"Newton's method",     kind:"procedure",  x:0.78, y:0.92, mastery:"locked", retention:null, due:null },
    { id:"linear_approx",  label:"Linear approximation",kind:"theorem",    x:0.90, y:0.86, mastery:"locked", retention:null, due:null },
  ];

  const edges = [
    ["set","function"],["function","limit_func"],["real_numbers","limit_seq"],
    ["limit_seq","limit_func"],["limit_func","epsilon_delta"],["limit_func","continuity"],
    ["limit_func","limit_sum"],["limit_func","limit_product"],["limit_func","limit_compose"],
    ["slope_line","secant"],["slope_line","diff_quot"],["function","secant"],
    ["composition","limit_compose"],["interval","derivative"],["absolute_val","continuity"],
    ["function","derivative"],["limit_func","derivative"],["diff_quot","derivative"],
    ["secant","derivative"],["continuity","derivative"],
    ["derivative","diff_implies_cont"],["derivative","sum_rule"],["derivative","product_rule"],["derivative","chain_rule"],
    ["limit_sum","sum_rule"],["limit_product","product_rule"],["limit_compose","chain_rule"],
    ["continuity","diff_implies_cont"],
    ["diff_implies_cont","mvt"],["derivative","mvt"],["derivative","l_hopital"],
    ["derivative","taylor"],["derivative","newtons_method"],["derivative","linear_approx"],
  ];

  const nodeById = Object.fromEntries(nodes.map(n => [n.id, n]));
  const counts = {
    mastered: nodes.filter(n => n.mastery==="mastered" && n.retention >= 0.7).length,
    review:   nodes.filter(n => n.due !== null && n.due < 0).length,
    learning: nodes.filter(n => n.mastery==="learning").length,
    frontier: nodes.filter(n => n.mastery==="frontier").length,
    locked:   nodes.filter(n => n.mastery==="locked").length,
  };

  // Effective state for visual encoding combines mastery + retention.
  const stateOf = (n) => {
    if (n.mastery === "frontier") return "frontier";
    if (n.mastery === "locked")   return "locked";
    if (n.mastery === "learning") return "learning";
    if (n.due !== null && n.due < 0) return "review";
    return "mastered";
  };

  const matchFilter = (n) => filter === "all" || stateOf(n) === filter;

  const W = 1180, H = 720;
  const PAD_X = 60, PAD_Y = 40;
  const xToPx = (x) => PAD_X + x * (W - 2*PAD_X);
  const yToPx = (y) => PAD_Y + y * (H - 2*PAD_Y);

  const reviewDue = nodes.filter(n => n.due !== null && n.due < 0).sort((a,b) => a.due - b.due);
  const frontier = nodes.filter(n => n.mastery === "frontier");

  return (
    <div className="mm">
      <header className="mm__top">
        <div className="mm__top-l">
          <span className="t-mono" style={{color:"var(--ink-4)"}}>§ MAP</span>
          <span className="cp__bc-sep">/</span>
          <span className="cp__bc-cur">Mastery map</span>
          <span className="cp__bc-sep">·</span>
          <span className="t-ui" style={{color:"var(--ink-3)"}}>your relationship to · Calculus / Differentiation</span>
        </div>
        <div className="mm__top-r">
          <span className="t-meta">Domain</span>
          <select className="mm__domain"><option>mathematics · calculus</option></select>
          <span className="cp__top-divider" />
          <button className="btn btn--ghost cp__top-btn">Export CLR</button>
          <button className="btn cp__top-btn">Start review (3) →</button>
        </div>
      </header>
      <hr className="rule" />

      <div className="mm__layout">
        {/* left rail — answers "what should I work on right now?" */}
        <aside className="mm__rail mm__rail--l">
          <div className="mm__what">
            <div className="t-meta">Right now</div>
            <hr className="rule-3" />
            <div className="mm__what-card mm__what-card--review">
              <div className="mm__what-head">
                <span className="mastery-dot mastery-dot--review" />
                <span className="t-meta">Review · {reviewDue.length} due</span>
                <span className="t-mono mm__what-time">~7 min</span>
              </div>
              <ul className="mm__what-list">
                {reviewDue.map(n => (
                  <li key={n.id} className="mm__what-item">
                    <span className="t-ui mm__what-label">{n.label}</span>
                    <span className="t-mono mm__what-meta">R {Math.round(n.retention*100)}% · {n.due}d</span>
                  </li>
                ))}
              </ul>
            </div>
            <div className="mm__what-card mm__what-card--frontier">
              <div className="mm__what-head">
                <span className="mastery-dot mastery-dot--frontier" />
                <span className="t-meta">Ready to learn · {frontier.length}</span>
              </div>
              <ul className="mm__what-list">
                {frontier.map(n => (
                  <li key={n.id} className="mm__what-item">
                    <span className="t-ui mm__what-label">{n.label}</span>
                    <span className="t-mono mm__what-meta">all prereqs met</span>
                  </li>
                ))}
              </ul>
            </div>
          </div>

          <div className="mm__legend">
            <div className="t-meta">State</div>
            <hr className="rule-3" />
            <ul className="mm__legend-list">
              <li><span className="mastery-dot mastery-dot--mastered" /><span className="t-ui">Mastered</span><span className="t-mono mm__legend-n">{counts.mastered}</span></li>
              <li><span className="mastery-dot mastery-dot--review" /><span className="t-ui">Review due</span><span className="t-mono mm__legend-n">{counts.review}</span></li>
              <li><span className="mastery-dot mastery-dot--learning" /><span className="t-ui">Learning</span><span className="t-mono mm__legend-n">{counts.learning}</span></li>
              <li><span className="mastery-dot mastery-dot--frontier" /><span className="t-ui">Frontier</span><span className="t-mono mm__legend-n">{counts.frontier}</span></li>
              <li><span className="mastery-dot mastery-dot--locked" /><span className="t-ui">Locked</span><span className="t-mono mm__legend-n">{counts.locked}</span></li>
            </ul>
            <hr className="rule-3" />
            <div className="t-meta" style={{marginTop:"8px"}}>Filter</div>
            <div className="mm__filter">
              {["all","review","frontier","learning","locked"].map(k => (
                <button key={k} className={"mm__filter-btn " + (filter===k?"is-on":"")} onClick={()=>setFilter(k)}>
                  {k}
                </button>
              ))}
            </div>
          </div>
        </aside>

        {/* main map */}
        <div className="mm__stage">
          <svg viewBox={`0 0 ${W} ${H}`} className="mm__svg" preserveAspectRatio="xMidYMid meet">
            <defs>
              <radialGradient id="mm-frontier-glow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0" stopColor="var(--accent)" stopOpacity="0.18"/>
                <stop offset="1" stopColor="var(--accent)" stopOpacity="0"/>
              </radialGradient>
              <radialGradient id="mm-review-glow" cx="0.5" cy="0.5" r="0.5">
                <stop offset="0" stopColor="var(--ink)" stopOpacity="0.10"/>
                <stop offset="1" stopColor="var(--ink)" stopOpacity="0"/>
              </radialGradient>
            </defs>

            {/* depth rules — territory bands */}
            {[0.20, 0.42, 0.58, 0.83].map((y, i) => (
              <line key={i} x1={PAD_X} y1={yToPx(y)} x2={W-PAD_X} y2={yToPx(y)}
                    stroke="var(--rule-3)" strokeWidth="0.5" strokeDasharray="2 4" />
            ))}
            <text x={PAD_X} y={yToPx(0.04)+4} fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-4)" letterSpacing="1">FOUNDATIONS</text>
            <text x={PAD_X} y={yToPx(0.24)+4} fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-4)" letterSpacing="1">LIMITS</text>
            <text x={PAD_X} y={yToPx(0.46)+4} fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-4)" letterSpacing="1">CONTINUITY · SECANTS</text>
            <text x={PAD_X} y={yToPx(0.62)+4} fontFamily="var(--font-mono)" fontSize="9" fill="var(--accent)" letterSpacing="1">FRONTIER</text>
            <text x={PAD_X} y={yToPx(0.86)+4} fontFamily="var(--font-mono)" fontSize="9" fill="var(--ink-5)" letterSpacing="1">LOCKED · DOWNSTREAM</text>

            {/* glow halos */}
            {nodes.filter(n => stateOf(n) === "frontier").map(n => (
              <circle key={"g-"+n.id} cx={xToPx(n.x)} cy={yToPx(n.y)} r="48" fill="url(#mm-frontier-glow)" />
            ))}
            {nodes.filter(n => stateOf(n) === "review").map(n => (
              <circle key={"g-"+n.id} cx={xToPx(n.x)} cy={yToPx(n.y)} r="36" fill="url(#mm-review-glow)" />
            ))}

            {/* edges */}
            <g>
              {edges.map(([a, b], i) => {
                const na = nodeById[a], nb = nodeById[b];
                if (!na || !nb) return null;
                const ax = xToPx(na.x), ay = yToPx(na.y);
                const bx = xToPx(nb.x), by = yToPx(nb.y);
                // both ends locked? mute
                const aSt = stateOf(na), bSt = stateOf(nb);
                const isLocked = aSt === "locked" || bSt === "locked";
                const isFrontier = aSt === "frontier" || bSt === "frontier";
                const stroke = isFrontier ? "var(--accent)" : isLocked ? "var(--rule-3)" : "var(--rule-2)";
                const opacity = isLocked ? 0.5 : isFrontier ? 0.6 : 0.5;
                const isHov = hovered && (a === hovered || b === hovered);
                return (
                  <line key={i} x1={ax} y1={ay} x2={bx} y2={by}
                        stroke={isHov ? "var(--accent)" : stroke}
                        strokeWidth={isHov ? 1.5 : 0.8}
                        opacity={hovered && !isHov ? 0.15 : opacity} />
                );
              })}
            </g>

            {/* nodes */}
            <g>
              {nodes.filter(matchFilter).map(n => {
                const st = stateOf(n);
                const cx = xToPx(n.x), cy = yToPx(n.y);
                const isHov = hovered === n.id;
                const dim = filter !== "all" && !matchFilter(n);
                const fill = st === "mastered" ? "var(--ink)"
                          : st === "frontier" ? "var(--accent)"
                          : st === "review" ? "var(--paper)"
                          : st === "learning" ? "var(--paper)"
                          : "var(--paper)";
                const stroke = st === "locked" ? "var(--rule-2)"
                            : st === "review" ? "var(--ink)"
                            : st === "learning" ? "var(--ink)"
                            : st === "frontier" ? "var(--accent)"
                            : "var(--ink)";
                const r = n.focus ? 7 : (n.kind==="theorem"||n.kind==="lemma") ? 0 : 4.5;
                return (
                  <g key={n.id}
                     onMouseEnter={()=>setHovered(n.id)}
                     onMouseLeave={()=>setHovered(null)}
                     style={{cursor:"pointer"}}
                     opacity={dim ? 0.2 : 1}>
                    {/* shape encodes type */}
                    {n.kind === "theorem" || n.kind === "lemma" ? (
                      <rect x={cx-5} y={cy-5} width="10" height="10" fill={fill} stroke={stroke} strokeWidth={n.focus?2:1.25} />
                    ) : n.kind === "axiom" ? (
                      <polygon points={`${cx},${cy-6} ${cx+6},${cy} ${cx},${cy+6} ${cx-6},${cy}`}
                               fill={fill} stroke={stroke} strokeWidth="1.25" />
                    ) : n.kind === "procedure" ? (
                      <polygon points={`${cx-6},${cy-4} ${cx+6},${cy-4} ${cx+4},${cy+4} ${cx-4},${cy+4}`}
                               fill={fill} stroke={stroke} strokeWidth="1.25" />
                    ) : (
                      <circle cx={cx} cy={cy} r={r} fill={fill} stroke={stroke} strokeWidth={n.focus?2:1.25} />
                    )}
                    {/* review hatch overlay */}
                    {st === "review" && (
                      <circle cx={cx} cy={cy} r="3" fill="var(--ink)" />
                    )}
                    {/* frontier focus halo */}
                    {n.focus && (
                      <circle cx={cx} cy={cy} r="14" fill="none" stroke="var(--accent)" strokeWidth="1" strokeDasharray="2 2"/>
                    )}
                    {/* retention bar — for nodes with retention */}
                    {n.retention !== null && st !== "frontier" && (
                      <g transform={`translate(${cx-12},${cy+10})`}>
                        <line x1="0" y1="0" x2="24" y2="0" stroke="var(--rule-3)" strokeWidth="2"/>
                        <line x1="0" y1="0" x2={24*n.retention} y2="0"
                              stroke={st === "review" ? "var(--accent)" : "var(--ink)"} strokeWidth="2"/>
                      </g>
                    )}
                    <text x={cx + 9} y={cy + 4}
                          fontFamily="var(--font-ui)" fontSize="10.5"
                          fontWeight={n.focus?600:500}
                          fill={st === "locked" ? "var(--ink-4)" : "var(--ink)"}>
                      {n.label}
                    </text>
                  </g>
                );
              })}
            </g>
          </svg>
        </div>

        {/* right rail — selected node detail */}
        <aside className="mm__rail mm__rail--r">
          <div className="t-meta">Selected</div>
          <hr className="rule-3" />
          {hovered ? (() => {
            const n = nodeById[hovered]; const st = stateOf(n);
            return (
              <div className="mm__sel">
                <div className="mm__sel-head">
                  <span className={"mastery-dot mastery-dot--" + st} />
                  <span className="type-chip" data-kind={n.kind}>{n.kind}</span>
                </div>
                <h3 className="t-h3 mm__sel-title">{n.label}</h3>
                <div className="t-mono mm__sel-id">{n.kind}.calc.{n.id}</div>
                <hr className="rule-3" style={{margin:"14px 0"}}/>
                {n.retention !== null ? (
                  <>
                    <div className="mm__sel-row"><span className="t-meta">FSRS retention</span><span className="t-mono">{Math.round(n.retention*100)}%</span></div>
                    <div className="mm__sel-row"><span className="t-meta">Due</span><span className="t-mono" style={{color: n.due<0?"var(--accent)":"var(--ink)"}}>{n.due<0?`${-n.due}d ago`:`in ${n.due}d`}</span></div>
                    <div className="mm__sel-row"><span className="t-meta">Stability</span><span className="t-mono">14.2d</span></div>
                    <div className="mm__sel-row"><span className="t-meta">Difficulty</span><span className="t-mono">5.1 / 10</span></div>
                  </>
                ) : (
                  <div className="t-ui" style={{color:"var(--ink-3)",fontStyle:"italic"}}>Not yet mastered. Begin to track retention.</div>
                )}
                <hr className="rule-3" style={{margin:"14px 0"}}/>
                <div className="t-meta">Mastery</div>
                <div className="mm__sel-mastery">
                  <span className="t-h2" style={{margin:0,color:"var(--ink)"}}>{
                    st==="mastered"?"94":st==="review"?"68":st==="learning"?"54":st==="frontier"?"00":"—"
                  }<span style={{fontSize:"24px",color:"var(--ink-4)"}}>%</span></span>
                  <span className="t-meta" style={{marginLeft:"auto"}}>BKT</span>
                </div>
                <hr className="rule-3" style={{margin:"14px 0"}}/>
                <button className="btn cp__top-btn" style={{width:"100%",justifyContent:"center"}}>
                  {st==="frontier"?"Begin learning →":st==="review"?"Review now →":"Open concept →"}
                </button>
              </div>
            );
          })() : (
            <div className="t-ui mm__sel-empty">
              Hover any node to see your relationship to that concept.
              <hr className="rule-3" style={{margin:"18px 0"}}/>
              <div className="t-meta" style={{marginBottom:"6px"}}>Streak</div>
              <div className="t-display" style={{fontSize:"56px",lineHeight:1,color:"var(--ink)"}}>14</div>
              <div className="t-meta" style={{marginTop:"4px"}}>days · 412 reviews</div>
              <hr className="rule-3" style={{margin:"18px 0"}}/>
              <div className="t-meta" style={{marginBottom:"6px"}}>Today</div>
              <div className="mm__sel-row"><span className="t-ui">Reviews due</span><span className="t-mono">3</span></div>
              <div className="mm__sel-row"><span className="t-ui">New concepts</span><span className="t-mono">2</span></div>
              <div className="mm__sel-row"><span className="t-ui">Avg retention</span><span className="t-mono">73%</span></div>
            </div>
          )}
        </aside>
      </div>

      <hr className="rule-2" />
      <footer className="pg__foot">
        <span className="t-meta">{nodes.length} concepts · {edges.length} edges · domain: mathematics</span>
        <span className="t-mono" style={{color:"var(--ink-4)"}}>FSRS-6 · 21 params · personalized · last sync 14:02 UTC</span>
      </footer>
    </div>
  );
};

window.MasteryMap = MasteryMap;
