/* ============================================================
   HALO SMS — Score entry grid (Batch 2, signature staff screen)
   students × CA/Exam · inline validation · live total/grade ·
   keyboard nav · save draft
   ============================================================ */
(function () {
  const { useState, useEffect, useRef, h } = window.HReact;
  const D = window.HALO;

  const ARMS = ["JSS 1A", "JSS 2B", "SS2 Science", "SS3 Arts", "Primary 4"];

  function initialScores(arm, subject, students, comps) {
    const roster = D.rosterForArm(arm, students);
    const rnd = D.seeded(arm + subject);
    const map = {};
    const armState = D.armState(arm);
    roster.forEach((s, i) => {
      if (armState === "none") { map[s.id] = { ca1: "", ca2: "", exam: "", absent: false }; return; }
      const absent = armState !== "published" && rnd() < 0.05;
      const blankExam = armState !== "published" && rnd() < 0.18; // some still being entered
      const base = 55 + Math.floor(rnd() * 35);
      map[s.id] = {
        ca1: String(Math.min(comps[0].max, Math.round(comps[0].max * (0.6 + rnd() * 0.4)))),
        ca2: String(Math.min(comps[1].max, Math.round(comps[1].max * (0.6 + rnd() * 0.4)))),
        exam: absent ? "" : (blankExam ? "" : String(Math.min(comps[2].max, Math.round(comps[2].max * (base / 100))))),
        absent,
      };
    });
    return map;
  }

  function ScoreEntry({ navigate, students, assess }) {
    const comps = (assess || D.ASSESSMENT).components;
    const [arm, setArm] = useState("JSS 1A");
    const [subject, setSubject] = useState(D.subjectsForArm("JSS 1A")[0]);
    const [scores, setScores] = useState(() => initialScores("JSS 1A", D.subjectsForArm("JSS 1A")[0], students, comps));
    const [dirty, setDirty] = useState(false);
    const subjects = D.subjectsForArm(arm);
    const roster = D.rosterForArm(arm, students);

    function reload(a, sub) { setScores(initialScores(a, sub, students, comps)); setDirty(false); }
    function onArm(e) { const a = e.target.value; setArm(a); const sub = D.subjectsForArm(a)[0]; setSubject(sub); reload(a, sub); }
    function onSubject(e) { const sub = e.target.value; setSubject(sub); reload(arm, sub); }

    function setCell(id, key, val) {
      const max = key === "ca1" ? comps[0].max : key === "ca2" ? comps[1].max : comps[2].max;
      val = val.replace(/[^0-9]/g, "");
      if (val !== "" && Number(val) > max) val = String(max); // clamp at max
      setScores((p) => ({ ...p, [id]: { ...p[id], [key]: val } })); setDirty(true);
    }
    function toggleAbsent(id) { setScores((p) => ({ ...p, [id]: { ...p[id], absent: !p[id].absent, exam: !p[id].absent ? "" : p[id].exam } })); setDirty(true); }

    function totalOf(r) { if (!r || r.absent) return null; const a = Number(r.ca1 || 0), b = Number(r.ca2 || 0), e = r.exam === "" ? null : Number(r.exam); if (e === null) return null; return a + b + e; }
    function key(e, rIdx, col) {
      const move = (dr) => { const el = document.querySelector(`input[data-r='${rIdx + dr}'][data-c='${col}']`); if (el) { el.focus(); el.select && el.select(); } };
      if (e.key === "ArrowDown" || e.key === "Enter") { e.preventDefault(); move(1); }
      else if (e.key === "ArrowUp") { e.preventDefault(); move(-1); }
    }

    const entered = roster.filter((s) => totalOf(scores[s.id]) !== null || scores[s.id]?.absent).length;
    const missing = roster.length - entered;

    return h("div", { className: "page-pad wide" },
      h(window.PageHead, { eyebrow: "Score entry · " + D.STRUCTURE.session, title: "Enter scores", sub: D.STRUCTURE.activeTerm + " · saves as draft until published" }),
      // selector + draft banner
      h("div", { className: "card", style: { padding: 16, marginBottom: 14, display: "flex", gap: 14, alignItems: "center", flexWrap: "wrap" } },
        h("div", { className: "field", style: { gap: 4 } }, h("label", { style: { fontSize: 12 } }, "Class / arm"),
          h("select", { className: "select", style: { width: 180, height: 40 }, value: arm, onChange: onArm }, ARMS.map((a) => h("option", { key: a }, a)))),
        h("div", { className: "field", style: { gap: 4 } }, h("label", { style: { fontSize: 12 } }, "Subject"),
          h("select", { className: "select", style: { width: 220, height: 40 }, value: subject, onChange: onSubject }, subjects.map((s) => h("option", { key: s }, s)))),
        h("div", { style: { flex: 1 } }),
        h("div", { style: { textAlign: "right" } },
          h("div", { className: "muted", style: { fontSize: 12 } }, "Entered"),
          h("div", { style: { fontFamily: "var(--fs-display)", fontWeight: 700, fontSize: 18 } }, entered + " / " + roster.length))),
      h("div", { className: "consequence", style: { marginBottom: 14, background: "var(--warn-bg)", borderColor: "var(--warn-line)", color: "var(--warn-fg)" } },
        h(Icon, { name: "alert", style: { fontSize: 17 } }),
        h("div", null, h("b", null, "Draft — not yet published."), " Scores are saved privately. Parents and students can't see them until an authorised teacher or the principal publishes this arm.")),

      roster.length === 0
        ? h("div", { className: "card" }, h(EmptyState, { icon: "clipboard", title: "No students in this arm" }, "Admit students to this class to enter scores."))
        : h("div", { className: "card", style: { overflow: "hidden" } },
            h("div", { className: "tablewrap" }, h("table", { className: "data scoregrid" },
              h("thead", null, h("tr", null,
                h("th", { style: { minWidth: 200 } }, "Student"),
                comps.map((c) => h("th", { key: c.id, className: "num" }, c.name + " /" + c.max)),
                h("th", { className: "num" }, "Total"),
                h("th", { className: "num" }, "Grade"),
                h("th", { className: "num" }, "Abs."))),
              h("tbody", null, roster.map((s, ri) => h(ScoreRow, { key: s.id, s, ri, comps, r: scores[s.id] || {}, setCell, toggleAbsent, totalOf, onKey: key, assess })))))),

      roster.length > 0 && h("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginTop: 16, flexWrap: "wrap", gap: 10 } },
        h("div", { className: "muted", style: { fontSize: 13 } }, missing > 0 ? h("span", null, h("b", { style: { color: "var(--warn-fg)" } }, missing + " students"), " still missing an exam score") : h("span", { style: { color: "var(--ok-fg)" } }, "All scores entered — ready to publish")),
        h("div", { className: "wrap-actions" },
          h(Button, { kind: "ghost", icon: "upload", onClick: () => navigate("scores:import") }, "Import scores"),
          h(Button, { kind: "primary", icon: "check", disabled: !dirty, onClick: () => { setDirty(false); toast("Scores saved as draft"); } }, dirty ? "Save draft" : "Saved"))));
  }

  function ScoreRow({ s, ri, comps, r, setCell, toggleAbsent, totalOf, onKey, assess }) {
    const total = totalOf(r);
    const g = total !== null ? D.gradeFor(total, (assess || D.ASSESSMENT).gradeBands) : null;
    const over = (key, max) => r[key] !== "" && r[key] != null && Number(r[key]) > max;
    return h("tr", { style: { cursor: "default" } },
      h("td", null, h("div", { className: "cellname" }, h(Avatar, { name: s.first + " " + s.surname, size: 30 }),
        h("div", null, h("div", { className: "nm", style: { fontSize: 13.5 } }, s.surname + ", " + s.first), h("div", { className: "sub" }, s.adm)))),
      comps.map((c, ci) => h("td", { key: c.id, className: "num", style: { padding: "6px 8px" } },
        r.absent && c.id === "exam"
          ? h("span", { className: "muted", style: { fontStyle: "italic", fontSize: 13 } }, "Abs.")
          : h("input", { className: "gridinput", "data-r": ri, "data-c": ci, value: r[c.id] || "", disabled: r.absent && c.id === "exam",
              onChange: (e) => setCell(s.id, c.id, e.target.value), onKeyDown: (e) => onKey(e, ri, ci), onFocus: (e) => e.target.select(),
              style: over(c.id, c.max) ? { borderColor: "var(--bad)", color: "var(--bad-fg)" } : null }))),
      h("td", { className: "num", style: { fontWeight: 700, fontVariantNumeric: "tabular-nums" } }, r.absent ? h("span", { className: "muted" }, "—") : total === null ? h("span", { className: "muted", style: { fontWeight: 400 } }, "·") : total),
      h("td", { className: "num" }, g ? h("span", { style: { fontWeight: 700, color: total >= 75 ? "var(--ok-fg)" : total < 50 ? "var(--bad-fg)" : "inherit" } }, g.grade) : h("span", { className: "muted" }, "—")),
      h("td", { className: "num" }, h("button", { onClick: () => toggleAbsent(s.id), className: "absbtn", title: "Toggle absent",
        style: { width: 26, height: 26, borderRadius: 7, border: "1px solid " + (r.absent ? "var(--bad)" : "var(--line)"), background: r.absent ? "var(--bad-bg)" : "var(--surface)", color: r.absent ? "var(--bad-fg)" : "var(--ink-400)", fontWeight: 700, fontSize: 12 } }, r.absent ? "A" : "")));
  }

  function ScoreEntryRouter({ params, navigate, students, assess }) {
    if (params[0] === "import") return h(window.BulkImport, { entity: "results", navigate, onDone: () => navigate("scores") });
    return h(ScoreEntry, { navigate, students, assess });
  }

  window.ScoreEntry = ScoreEntryRouter;
})();
