// =====================================================================
// irikos — Teacher side of Classrooms.
// ClassroomsHome · CreateClassroom · ClassroomDetail (Roster / Progress /
// Homework / My tasks) · StudentDetail · AssignmentBuilder · TaskEditor.
// Globals: React, store helpers, shared components, VOCAB/CATEGORY_META/
// FAMILY_META/FAMILY_ORDER.
// =====================================================================

const { useState: tUseState, useMemo: tUseMemo } = React;

// ---------------------------------------------------------------------
// Root router for the teacher Class area
// ---------------------------------------------------------------------
function TeacherClass({ store, actions, account, pushToast, dataState, initial, onOpenStudents }) {
  const [view, setView] = tUseState(initial || { name: "list" });
  const myClassrooms = Object.values(store.classrooms).filter(c => c.ownerHandle === account.handle || c.ownerHandle === "teacher");

  if (view.name === "detail" && store.classrooms[view.classId]) {
    return (
      <ClassroomDetail
        store={store} actions={actions} pushToast={pushToast}
        classId={view.classId} initialTab={view.tab}
        onBack={() => setView({ name: "list" })}
      />
    );
  }
  return (
    <ClassroomsHome
      store={store} actions={actions} account={account} pushToast={pushToast}
      classrooms={myClassrooms} dataState={dataState}
      onOpen={(classId) => setView({ name: "detail", classId })}
      onOpenStudents={onOpenStudents}
    />
  );
}

// ---------------------------------------------------------------------
// Classrooms home — a card per classroom + create
// ---------------------------------------------------------------------
function ClassroomsHome({ store, actions, account, pushToast, classrooms, dataState, onOpen, onOpenStudents }) {
  const [creating, setCreating] = tUseState(false);

  return (
    <div className="class-shell">
      <header className="class-head">
        <div className="class-head-l">
          <h1 className="class-title">Classrooms</h1>
          <span className="role-chip">Teacher</span>
        </div>
        <div className="class-head-actions" style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
          {onOpenStudents && (
            <button className="cta-secondary" onClick={onOpenStudents}>
              <span>All students</span>
            </button>
          )}
          {dataState === "ready" && classrooms.length > 0 && (
            <button className="cta-primary" onClick={() => setCreating(true)}>
              <span>Create classroom</span><span className="cta-arrow">+</span>
            </button>
          )}
        </div>
      </header>

      {dataState === "loading" && <SkeletonCards n={3} />}
      {dataState === "error" && <ErrorState onRetry={() => pushToast("Reconnected")}>Your classrooms didn't sync. Check your connection and try again.</ErrorState>}

      {dataState === "ready" && classrooms.length === 0 && (
        <EmptyState icon="+" title="No classrooms yet"
          cta={<button className="cta-primary" onClick={() => setCreating(true)}><span>Create your first classroom</span><span className="cta-arrow">+</span></button>}>
          A classroom is where you invite students by @username, assign homework from the practice pools, and watch progress build — auto-scored, no marking.
        </EmptyState>
      )}

      {dataState === "ready" && classrooms.length > 0 && (
        <div className="cls-grid">
          {classrooms.map(c => {
            const flags = classFlags(store, c.id);
            const nStudents = c.studentCount != null ? c.studentCount : c.studentHandles.length;
            return (
              <button className="cls-card" key={c.id} onClick={() => onOpen(c.id)}>
                <div className="cls-card-top">
                  <div>
                    <div className="cls-card-name">{c.name}</div>
                    <div className="cls-card-meta">{nStudents} student{nStudents === 1 ? "" : "s"} · created {relTime(c.createdAt)}</div>
                  </div>
                  <div className="avatar-stack">
                    {c.studentHandles.slice(0, 3).map(h => store.directory[h] && (
                      <Avatar key={h} name={store.directory[h].name} hue={store.directory[h].avatarHue} size="sm" />
                    ))}
                  </div>
                </div>
                <div className="cls-card-foot">
                  <div className="cls-card-badges">
                    {flags.needsReview > 0 && <span className="badge is-review"><span className="dot" />{flags.needsReview} needs review</span>}
                    {flags.overdue > 0 && <span className="badge is-overdue"><span className="dot" />{flags.overdue} overdue</span>}
                    {flags.pending > 0 && <span className="badge is-pending"><span className="dot" />{flags.pending} pending</span>}
                    {flags.needsReview === 0 && flags.overdue === 0 && flags.pending === 0 && <span className="badge is-ok"><span className="dot" />all clear</span>}
                  </div>
                  <span className="mono-sm nowrap">{c.code}</span>
                </div>
              </button>
            );
          })}
          <button className="cls-create" onClick={() => setCreating(true)}>
            <span className="role-card-icon" style={{ background: "var(--card)" }}>
              <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M12 5v14M5 12h14" /></svg>
            </span>
            <span className="cls-create-h">Create classroom</span>
            <span className="cls-create-s">Name it, share the code, invite by @username.</span>
          </button>
        </div>
      )}

      {creating && (
        <CreateClassroom store={store} actions={actions} pushToast={pushToast} onClose={() => setCreating(false)} onOpen={onOpen} />
      )}
    </div>
  );
}

// ---------------------------------------------------------------------
// Create classroom — name only → success shows code + invite box
// ---------------------------------------------------------------------
function CreateClassroom({ store, actions, pushToast, onClose, onOpen }) {
  const [name, setName] = tUseState("");
  const [exam, setExam] = tUseState("ege");
  const [created, setCreated] = tUseState(null); // { id, code }
  const [busy, setBusy] = tUseState(false);      // for the button label/disabled state
  // Synchronous lock: a state flag won't block a second tap fired in the same
  // render tick (state hasn't updated yet), which is exactly how the double
  // POST — two classrooms, two join codes — was happening.
  const creatingRef = React.useRef(false);

  const create = async () => {
    if (creatingRef.current || created) return;  // one create per submit
    if (name.trim().length < 2) return;
    creatingRef.current = true;
    setBusy(true);
    try {
      const res = await actions.createClassroom(name, exam);
      if (res) setCreated(res);
    } finally {
      creatingRef.current = false;
      setBusy(false);
    }
  };

  if (created) {
    return (
      <Modal title="Classroom ready" sub={name.trim()} onClose={onClose}
        foot={<>
          <button className="cta-secondary" onClick={onClose}>Later</button>
          <button className="cta-primary" onClick={() => { onClose(); onOpen(created.id); }}><span>Open classroom</span><span className="cta-arrow">→</span></button>
        </>}>
        <div className="modal-success">
          <div className="modal-success-mark">✓</div>
        </div>
        <div className="build-label">Share this join code</div>
        <div className="build-hint">Students enter it under Class → Join to add themselves — no invite needed.</div>
        <JoinCode code={created.code} />
        <div className="divider-h" />
        <div className="build-label">Or invite by username</div>
        <div className="build-hint">They'll get a request to share their practice stats with you.</div>
        <AtAutocomplete directory={store.directory} exclude={[]} placeholder="invite a student"
          onPick={async (h) => { const r = await actions.addStudent(created.id, h); pushToast(r && r.ok === false ? r.err : `Invited @${h}`); }} />
      </Modal>
    );
  }

  return (
    <Modal title="Create a classroom" sub="You can invite students next." onClose={onClose}
      foot={<>
        <button className="cta-secondary" onClick={onClose}>Cancel</button>
        <button className="cta-primary" onClick={create} disabled={busy || name.trim().length < 2}><span>{busy ? "Creating…" : "Create"}</span><span className="cta-arrow">→</span></button>
      </>}>
      <div className="build-label">Classroom name</div>
      <input className="field-input" autoFocus value={name} onChange={e => setName(e.target.value)}
        onKeyDown={e => e.key === "Enter" && create()} placeholder="e.g. 9B — English" maxLength={48} />
      <div className="build-label" style={{ marginTop: 16 }}>Exam</div>
      <div className="build-hint">Which exam this class practises for — scopes assignable content and the stats you see. You can switch it any time.</div>
      <div role="radiogroup" aria-label="Exam" style={{ display: "inline-flex", background: "rgba(128,128,128,0.16)", borderRadius: 999, padding: 3, gap: 2 }}>
        {[["ege", "ЕГЭ"], ["oge", "ОГЭ"]].map(([v, l]) => {
          const on = exam === v;
          return (
            <button key={v} type="button" role="radio" aria-checked={on} onClick={() => setExam(v)}
              style={{ border: "none", cursor: "pointer", borderRadius: 999, padding: "6px 18px", fontWeight: 700, fontSize: 14,
                background: on ? "var(--accent)" : "transparent", color: on ? "#fff" : "var(--ink-3, #8a8f98)" }}>
              {l}
            </button>
          );
        })}
      </div>
    </Modal>
  );
}

// ---------------------------------------------------------------------
// Classroom detail — tabbed
// ---------------------------------------------------------------------
function ClassroomDetail({ store, actions, pushToast, classId, onBack, initialTab }) {
  const c = store.classrooms[classId];
  const [tab, setTab] = tUseState(initialTab || "roster");
  const [student, setStudent] = tUseState(null);
  const ov = classOverview(store, classId);
  const classAssignments = ov.assignments;

  const [confirmDelete, setConfirmDelete] = tUseState(false);
  const [deleting, setDeleting] = tUseState(false);
  const deletingRef = React.useRef(false);   // synchronous lock (one delete)
  const doDelete = async () => {
    if (deletingRef.current) return;
    deletingRef.current = true;
    setDeleting(true);
    try {
      await actions.deleteClassroom(classId);
      pushToast("Classroom deleted");
      onBack();
    } finally {
      deletingRef.current = false;
      setDeleting(false);
    }
  };

  const tabs = [
    { id: "roster", label: "Roster", count: c.studentHandles.length },
    { id: "progress", label: "Progress" },
    { id: "homework", label: "Homework", count: classAssignments.length },
    { id: "tasks", label: "My tasks", count: Object.keys(store.tasks).length },
  ];

  if (student) {
    return <StudentDetail store={store} actions={actions} pushToast={pushToast}
      handle={student} classId={classId} onBack={() => setStudent(null)} />;
  }

  return (
    <div className="class-shell">
      <button className="back-link" onClick={onBack}><span className="arr">←</span> All classrooms</button>
      <header className="class-head">
        <div className="class-head-l">
          <h1 className="class-title">{c.name}</h1>
          <span className="role-chip">Teacher</span>
        </div>
        <div className="class-head-actions" style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
          <div role="radiogroup" aria-label="Class exam" title="Switch this class between ЕГЭ and ОГЭ — homework and stats follow the chosen exam"
            style={{ display: "inline-flex", background: "rgba(128,128,128,0.16)", borderRadius: 999, padding: 3, gap: 2 }}>
            {[["ege", "ЕГЭ"], ["oge", "ОГЭ"]].map(([v, l]) => {
              const on = (c.exam || "ege") === v;
              return (
                <button key={v} role="radio" aria-checked={on}
                  onClick={() => { if (!on) { actions.setClassroomExam(classId, v); pushToast(`Class switched to ${v === "oge" ? "ОГЭ" : "ЕГЭ"}`); } }}
                  style={{ border: "none", cursor: on ? "default" : "pointer", borderRadius: 999, padding: "5px 13px", fontWeight: 700, fontSize: 13, lineHeight: 1.2,
                    background: on ? "var(--accent)" : "transparent", color: on ? "#fff" : "var(--ink-3, #8a8f98)", transition: "background .12s" }}>
                  {l}
                </button>
              );
            })}
          </div>
          <JoinCode code={c.code} onRotate={() => { actions.rotateCode(classId); pushToast("New join code generated"); }} />
          <button className="icon-btn danger" title="Delete classroom" aria-label="Delete classroom" onClick={() => setConfirmDelete(true)}>
            <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6" /></svg>
          </button>
        </div>
      </header>

      <Tabs tabs={tabs} active={tab} onChange={setTab} />

      {confirmDelete && (
        <Modal title="Delete this classroom?" sub={c.name} onClose={() => { if (!deleting) setConfirmDelete(false); }}
          foot={<>
            <button className="cta-secondary" onClick={() => setConfirmDelete(false)} disabled={deleting}>Cancel</button>
            <button className="cta-primary" style={{ background: "var(--no)" }} onClick={doDelete} disabled={deleting}>
              <span>{deleting ? "Deleting…" : "Delete"}</span><span className="cta-arrow">→</span>
            </button>
          </>}>
          This permanently removes <b>{c.name}</b>, its roster, and all assignments and submissions for everyone. This can't be undone.
        </Modal>
      )}

      {tab === "roster" && <RosterTab store={store} actions={actions} pushToast={pushToast} c={c} />}
      {tab === "progress" && <ProgressTab ov={ov} store={store} classAssignments={classAssignments} onOpenStudent={setStudent} />}
      {tab === "homework" && <HomeworkTab store={store} actions={actions} pushToast={pushToast} c={c} assignments={classAssignments} />}
      {tab === "tasks" && <MyTasksTab store={store} actions={actions} pushToast={pushToast} />}
    </div>
  );
}

// ---------------------------------------------------------------------
// Roster tab
// ---------------------------------------------------------------------
function RosterTab({ store, actions, pushToast, c }) {
  const [confirm, setConfirm] = tUseState(null);
  const exclude = [...c.studentHandles, ...c.pendingInvites.map(p => p.handle), c.ownerHandle];

  return (
    <>
      <div className="panel panel-pad" style={{ marginBottom: 14 }}>
        <div className="section-label">Add a student</div>
        <div className="roster-toolbar">
          <AtAutocomplete directory={store.directory} exclude={exclude}
            onPick={async (h) => { const r = await actions.addStudent(c.id, h); pushToast(r && r.ok === false ? r.err : `Invited @${h}`); }} />
        </div>
        <div className="build-hint" style={{ margin: 0 }}>Type a synced <b>@username</b> to invite, or share the join code <b>{c.code}</b> so students add themselves.</div>
      </div>

      {c.studentHandles.length === 0 && c.pendingInvites.length === 0 ? (
        <EmptyState icon="○" title="No students yet"
          cta={<JoinCode code={c.code} onRotate={() => actions.rotateCode(c.id)} />}>
          Invite by @ above or share your code. Stats and homework appear here the moment they join.
        </EmptyState>
      ) : (
        <>
          {c.studentHandles.length > 0 && (
            <div className="panel" style={{ marginBottom: 14 }}>
              <div className="panel-head"><h3>Members</h3><span className="muted">{c.studentHandles.length}</span></div>
              {c.studentHandles.map(h => {
                const p = store.directory[h];
                if (!p) return null;
                return (
                  <div className="person-row" key={h}>
                    <Avatar name={p.name} hue={p.avatarHue} />
                    <div className="person-id">
                      <div className="person-name">{p.name}</div>
                      <div className="person-handle">@{p.handle}</div>
                    </div>
                    <div className="person-meta">{seenLabel(p.lastSeenDaysAgo)}</div>
                    <div className="person-actions">
                      <button className="icon-btn danger" aria-label={`Remove ${p.name}`} title="Remove" onClick={() => setConfirm(h)}>
                        <svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6" /></svg>
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          )}

          {c.pendingInvites.length > 0 && (
            <div className="panel">
              <div className="panel-head"><h3>Pending invites</h3><span className="muted">{c.pendingInvites.length}</span></div>
              {c.pendingInvites.map(inv => {
                const p = store.directory[inv.handle];
                return (
                  <div className="invite-row" key={inv.handle}>
                    {p ? <Avatar name={p.name} hue={p.avatarHue} size="sm" /> : <div className="avatar sm" style={{ background: "var(--ink-4)" }}>?</div>}
                    <div className="person-id">
                      <div className="person-name">{p ? p.name : `@${inv.handle}`}</div>
                      <div className="person-handle">@{inv.handle} · invited {relTime(inv.invitedAt)}</div>
                    </div>
                    <span className={`invite-status ${inv.status === "no-account" ? "is-noacct" : "is-pending"}`}>
                      {inv.status === "no-account" ? "No account found" : "Awaiting accept"}
                    </span>
                    <button className="text-link danger" onClick={() => { actions.cancelInvite(c.id, inv.handle); pushToast("Invite cancelled"); }}>Cancel</button>
                  </div>
                );
              })}
            </div>
          )}
        </>
      )}

      {confirm && (
        <Modal title="Remove student?" sub={`@${confirm} will lose access to this class.`} onClose={() => setConfirm(null)}
          foot={<>
            <button className="cta-secondary" onClick={() => setConfirm(null)}>Keep</button>
            <button className="cta-primary" style={{ background: "var(--no)" }} onClick={() => { actions.removeStudent(c.id, confirm); pushToast("Student removed"); setConfirm(null); }}>
              <span>Remove</span><span className="cta-arrow">→</span>
            </button>
          </>}>
          Their past homework submissions stay on record, but they'll no longer see new assignments. They can rejoin with the code.
        </Modal>
      )}
    </>
  );
}

// ---------------------------------------------------------------------
// Progress tab — class overview + sortable student table
// ---------------------------------------------------------------------
function ProgressTab({ ov, store, classAssignments, onOpenStudent }) {
  const [sortKey, setSortKey] = tUseState("accuracy");
  const [dir, setDir] = tUseState("desc");

  if (ov.studentCount === 0) {
    return <EmptyState icon="○" title="No data yet">Once students join and start practising, their accuracy by family, activity and homework completion roll up here.</EmptyState>;
  }

  // per-student homework counts
  const hwCount = (h) => {
    let total = 0, done = 0;
    for (const a of classAssignments) {
      if (a.submissions[h]) { total++; if (a.submissions[h].status === "completed") done++; }
    }
    return { total, done };
  };

  const rows = ov.students.map(p => {
    const hw = hwCount(p.handle);
    return { p, hw, hwFrac: hw.total ? hw.done / hw.total : 0 };
  });
  rows.sort((a, b) => {
    let av, bv;
    if (sortKey === "name") { av = a.p.name; bv = b.p.name; return dir === "asc" ? av.localeCompare(bv) : bv.localeCompare(av); }
    if (sortKey === "homework") { av = a.hwFrac; bv = b.hwFrac; }
    else if (sortKey === "lastSeen") { av = -a.p.lastSeenDaysAgo; bv = -b.p.lastSeenDaysAgo; }
    else av = a.p.accuracy, bv = b.p.accuracy;
    return dir === "asc" ? av - bv : bv - av;
  });
  const setSort = (k) => { if (sortKey === k) setDir(d => d === "asc" ? "desc" : "asc"); else { setSortKey(k); setDir(k === "name" ? "asc" : "desc"); } };
  const arrow = (k) => sortKey === k ? <span className="sort-arr">{dir === "asc" ? "▲" : "▼"}</span> : null;

  return (
    <>
      <section className="stats-row" style={{ gridTemplateColumns: "repeat(4,1fr)" }}>
        <BigStat label="Students" value={ov.studentCount} />
        <BigStat label="Active today" value={ov.activeToday} sub={`of ${ov.studentCount}`} />
        <BigStat label="Class accuracy" value={`${Math.round(ov.students.reduce((s, p) => s + p.accuracy, 0) / ov.studentCount * 100)}%`} />
        <BigStat label="Homework done" value={`${Math.round(ov.completion * 100)}%`} sub={`${ov.done}/${ov.due} submissions`} />
      </section>

      <div className="overview-grid">
        <section className="panel panel-pad">
          <div className="section-label">Accuracy by family · whole class</div>
          <FamilyBars byFamily={ov.byFamily} />
        </section>
        <section className="panel panel-pad">
          <div className="section-label">Homework completion</div>
          <div className="completion-ring">
            <CompletionRing frac={ov.completion}>{Math.round(ov.completion * 100)}%</CompletionRing>
            <div className="completion-meta">
              <div><b>{ov.done}</b> of <b>{ov.due}</b> submissions in</div>
              <div><b>{classAssignments.length}</b>{" "}assignment{classAssignments.length === 1 ? "" : "s"} live</div>
              <div><b>{ov.activeToday}</b>{" "}active today</div>
            </div>
          </div>
        </section>
      </div>

      <section className="panel">
        <div className="panel-head"><h3>Students</h3><span className="muted">tap a row for the full picture</span></div>
        <div className="table-scroll">
          <table className="stable">
            <thead>
              <tr>
                <th className="sortable" onClick={() => setSort("name")}>Student {arrow("name")}</th>
                <th className="num sortable" onClick={() => setSort("accuracy")}>Accuracy {arrow("accuracy")}</th>
                <th className="num hide-sm">Word form.</th>
                <th className="num hide-sm">Grammar</th>
                <th className="num hide-sm">Lexical</th>
                <th className="num sortable" onClick={() => setSort("homework")}>Homework {arrow("homework")}</th>
                <th className="sortable" onClick={() => setSort("lastSeen")}>Last seen {arrow("lastSeen")}</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(({ p, hw }) => (
                <tr key={p.handle} onClick={() => onOpenStudent(p.handle)}>
                  <td>
                    <div className="st-name">
                      <Avatar name={p.name} hue={p.avatarHue} size="sm" />
                      <span className="stack-sm" style={{ gap: 1 }}>
                        <span className="nm">{p.name}</span>
                        <span className="hd">@{p.handle}</span>
                      </span>
                    </div>
                  </td>
                  <td className="num"><span className="acc-pill" data-lvl={accLvl(p.accuracy)}>{Math.round(p.accuracy * 100)}%</span></td>
                  <td className="num hide-sm">{Math.round(p.byFamily["word-formation"].acc * 100)}%</td>
                  <td className="num hide-sm">{Math.round(p.byFamily["grammar"].acc * 100)}%</td>
                  <td className="num hide-sm">{Math.round(p.byFamily["multiple-choice"].acc * 100)}%</td>
                  <td className="num">{hw.total ? `${hw.done}/${hw.total}` : "—"}</td>
                  <td><span className={`last-seen ${p.lastSeenDaysAgo === 0 ? "is-today" : ""}`}>{seenLabel(p.lastSeenDaysAgo)}</span></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>
    </>
  );
}

// ---------------------------------------------------------------------
// Per-student view
// ---------------------------------------------------------------------
function StudentDetail({ store, actions, pushToast, handle, classId, onBack }) {
  React.useEffect(() => { actions.ensureStudentDetail && actions.ensureStudentDetail(classId, handle); }, [classId, handle]);
  const [reviewSession, setReviewSession] = React.useState(null);
  const p = store.directory[handle];
  if (!p) {
    return <div className="class-shell"><button className="back-link" onClick={onBack}><span className="arr">←</span> Back to class</button><SkeletonRows n={3} /></div>;
  }
  const subs = Object.values(store.assignments)
    .filter(a => a.classroomId === classId && a.submissions[handle])
    .map(a => ({ a, sub: a.submissions[handle] }));
  const mistakes = (p.mistakes || []).map(m => ({ ...m, item: VOCAB.find(v => v.id === m.id) })).filter(m => m.item).slice(0, 6);

  return (
    <div className="class-shell">
      <button className="back-link" onClick={onBack}><span className="arr">←</span> Back to class</button>
      <div className="sd-head">
        <Avatar name={p.name} hue={p.avatarHue} size="lg" />
        <div>
          <div className="sd-name">{p.name}</div>
          <div className="sd-handle">
            @{p.handle}
            <span className="sd-exam-badge">{p.exam === "oge" ? "ОГЭ" : "ЕГЭ"}</span>
            {p.otherExam ? <span className="sd-otherexam">also practising {p.otherExam.exam === "oge" ? "ОГЭ" : "ЕГЭ"} · {p.otherExam.totalAnswered} answered</span> : null}
          </div>
        </div>
        <span className="grow" />
        <span className={`last-seen ${p.lastSeenDaysAgo === 0 ? "is-today" : ""}`} style={{ fontSize: 13 }}>{seenLabel(p.lastSeenDaysAgo)}</span>
      </div>

      <section className="stats-row" style={{ gridTemplateColumns: "repeat(4,1fr)" }}>
        <BigStat label="All-time points" value={(p.totalScore || 0).toLocaleString()} accent />
        <BigStat label="Answered" value={p.totalAnswered} />
        <BigStat label="Accuracy" value={`${Math.round(p.accuracy * 100)}%`} />
        <BigStat label="Day streak" value={p.dayStreak} sub={p.dayStreak === 1 ? "day" : "days"} />
      </section>

      <div className="sd-grid">
        <section className="panel panel-pad">
          <div className="section-label">Accuracy by family</div>
          <FamilyBars byFamily={p.byFamily} />
        </section>
        <section className="panel panel-pad">
          <div className="section-label">Answers over the last 14 days</div>
          <MiniChart series={p.series} />
          <div className="legend" style={{ marginTop: 12 }}><span className="legend-dot is-bar" /> answered <span className="legend-dot is-line" /> accuracy</div>
        </section>
      </div>

      {Array.isArray(p.sessions) && p.sessions.length > 0 && (
        <section className="panel" style={{ marginBottom: 14 }}>
          <div className="panel-head"><h3>Recent sessions</h3><span className="muted">tap a set to review every task</span></div>
          <SessionsTable sessions={p.sessions} onOpenSession={setReviewSession} />
        </section>
      )}

      <section className="panel" style={{ marginBottom: 14 }}>
        <div className="panel-head"><h3>Homework</h3><span className="muted">{subs.filter(s => s.sub.status === "completed").length}/{subs.length} done</span></div>
        {subs.length === 0 ? <div className="panel-pad"><p className="muted" style={{ margin: 0 }}>No homework assigned to this student yet.</p></div> : subs.map(({ a, sub }) => (
          <div className="hw-row" key={a.id} style={{ cursor: "default" }}>
            <div className="hw-main">
              <div className="hw-title">{a.title}</div>
              <div className="hw-meta"><span>{assignmentLabel(a.kind)}</span></div>
            </div>
            <div className="hw-right">
              {sub.status === "completed"
                ? <><div className="hw-count">{sub.correct}/{sub.total}</div><span className="acc-pill" data-lvl={accLvl(sub.accuracy)}>{Math.round(sub.accuracy * 100)}%</span></>
                : <StatusPill status={sub.status} />}
            </div>
          </div>
        ))}
      </section>

      <section className="panel">
        <div className="panel-head"><h3>Mistakes</h3><span className="muted">most-missed first</span></div>
        {mistakes.length === 0 ? <div className="panel-pad"><p className="muted" style={{ margin: 0 }}>No mistakes on record — nicely done.</p></div> : (
          <div className="panel-pad" style={{ paddingTop: 14 }}>
            <ul className="mistake-list">
              {mistakes.map(m => (
                <li className="mistake-row" key={m.id}>
                  <div className="mistake-main">
                    <div className="mistake-eyebrow">
                      <span className="task-tag" data-task={m.item.type}>{FAMILY_META[m.item.type]?.label}</span>
                      {m.item.base && <span className="mistake-base">{m.item.base}</span>}
                    </div>
                    <div className="mistake-sentence">{(m.item.sentence || m.item.text || "").replace(/⟦\d+⟧/g, " ______ ").replace(/_{2,}/g, "______")}</div>
                    {m.wrote ? <div className="mistake-wrote">Wrote <s>{m.wrote}</s></div> : null}
                    <div className="mistake-answer">Answer <b>{m.item.gaps ? m.item.gaps.map(g => g.answer).join(", ") : m.item.answer}</b></div>
                  </div>
                  <div className="mistake-meta">
                    <div className="mistake-miss">{m.misses}×</div>
                    <div className="mistake-misslabel">missed</div>
                  </div>
                </li>
              ))}
            </ul>
          </div>
        )}
      </section>

      {reviewSession && window.SessionReviewModal
        ? <window.SessionReviewModal session={reviewSession} onClose={() => setReviewSession(null)} />
        : null}
    </div>
  );
}

function sdSessionDate(ts) {
  if (!ts) return "—";
  const d = new Date(ts), now = new Date();
  const k = (x) => Math.floor(Date.UTC(x.getFullYear(), x.getMonth(), x.getDate()) / 86400000);
  const diff = k(now) - k(d);
  if (diff <= 0) return "Today";
  if (diff === 1) return "Yesterday";
  if (diff < 7) return `${diff}d ago`;
  return d.toLocaleDateString(undefined, { day: "numeric", month: "short" });
}
function sdDuration(ms) {
  const s = Math.round((ms || 0) / 1000);
  return `${Math.floor(s / 60)}m ${String(s % 60).padStart(2, "0")}s`;
}
function sdSessionActivity(sess) {
  const qs = sess.questions || [];
  if (!qs.length) return "Practice";
  const seen = new Set();
  for (const q of qs) {
    const it = VOCAB.find(v => v.id === q.id);
    if (it) seen.add((FAMILY_META[it.type] || {}).label || it.type);
  }
  if (seen.size === 0) return "Practice";
  if (seen.size > 1) return "Mixed set";
  return [...seen][0];
}
function SessionsTable({ sessions, onOpenSession }) {
  return (
    <div className="sd-sessions">
      <table className="sd-sess-table">
        <thead><tr><th>Date</th><th>Activity</th><th className="num">Score</th><th className="num">Accuracy</th><th className="num">Time</th><th className="num">Points</th></tr></thead>
        <tbody>
          {sessions.map((s, i) => {
            const acc = Math.round((s.accuracy != null ? s.accuracy : (s.total ? s.correct / s.total : 0)) * 100);
            const hw = s.source === "homework";
            const reviewable = Array.isArray(s.questions) && s.questions.length > 0;
            return (
              <tr key={i} className="is-reviewable"
                  onClick={() => onOpenSession(s)}
                  title={reviewable ? "Review every task in this set" : "Per-task detail isn't kept for this set"}>
                <td className="sd-sess-date">{sdSessionDate(s.ts)}</td>
                <td><span className={`sess-tag ${hw ? "is-hw" : "is-self"}`}>{hw ? "HW" : "Self"}</span> {sdSessionActivity(s)}<span className="sess-review-arrow" aria-hidden="true">›</span></td>
                <td className="num">{s.correct}/{s.total}</td>
                <td className="num"><span className="acc-pill" data-lvl={accLvl(acc / 100)}>{acc}%</span></td>
                <td className="num sd-sess-muted">{sdDuration(s.durationMs)}</td>
                <td className="num sd-sess-pts">+{s.score || 0}</td>
              </tr>
            );
          })}
        </tbody>
      </table>
    </div>
  );
}

// ---------------------------------------------------------------------
// Homework tab + assignment builder
// ---------------------------------------------------------------------
function HomeworkTab({ store, actions, pushToast, c, assignments }) {
  const [building, setBuilding] = tUseState(false);
  const [feedbackFor, setFeedbackFor] = tUseState(null);
  // Completed submissions the teacher hasn't acknowledged yet.
  const needsReview = assignments.reduce((nn, a) =>
    nn + Object.values(a.submissions || {}).filter(s => s.status === "completed" && !s.seen).length, 0);

  return (
    <>
      <div className="row-gap" style={{ justifyContent: "space-between", marginBottom: 14, gap: 8, flexWrap: "wrap" }}>
        <div className="section-label" style={{ margin: 0 }}>{assignments.length} assignment{assignments.length === 1 ? "" : "s"}</div>
        <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
          {needsReview > 0 && (
            <button className="cta-secondary" onClick={() => { actions.markAllSeen(c.id); pushToast(`Marked ${needsReview} as seen`); }}>
              Mark all seen ({needsReview})
            </button>
          )}
          <button className="cta-primary" onClick={() => setBuilding(true)}><span>New assignment</span><span className="cta-arrow">+</span></button>
        </div>
      </div>

      {assignments.length === 0 ? (
        <EmptyState icon="+" title="No homework yet"
          cta={<button className="cta-primary" onClick={() => setBuilding(true)}><span>Build an assignment</span><span className="cta-arrow">+</span></button>}>
          Assign a set from any family, a full test, or one of your own tasks. Everything auto-scores — no marking, just an optional note back.
        </EmptyState>
      ) : (
        <div className="panel">
          {assignments.map(a => {
            const subs = Object.values(a.submissions);
            const done = subs.filter(s => s.status === "completed").length;
            const overdue = subs.filter(s => s.status === "overdue").length;
            return (
              <button className="hw-row" key={a.id} onClick={() => setFeedbackFor(a.id)}>
                <div className="hw-main">
                  <div className="hw-eyebrow">
                    <span className="task-tag" data-task={a.kind.type === "set" ? a.kind.family : (a.kind.type === "test" ? CATEGORY_META[a.kind.categoryId]?.family : "word-formation")}>{assignmentLabel(a.kind)}</span>
                    {a.assignedTo !== "all" && <span className="badge">{a.assignedTo.length} selected</span>}
                  </div>
                  <div className="hw-title">{a.title}</div>
                  {a.note && <div className="hw-note">{a.note}</div>}
                  <div className="hw-meta">
                    <span className={`hw-due ${overdue > 0 ? "is-overdue" : ""}`}>Due {fmtDue(a.dueDate)}</span>
                    <span className="hw-progress-mini"><span className="hw-mini-track"><span className="hw-mini-fill" style={{ width: `${subs.length ? done / subs.length * 100 : 0}%` }} /></span></span>
                  </div>
                </div>
                <div className="hw-right">
                  <div className="hw-count">{done}<small>/{subs.length} done</small></div>
                  {overdue > 0 && <span className="badge is-overdue"><span className="dot" />{overdue} overdue</span>}
                </div>
              </button>
            );
          })}
        </div>
      )}

      {building && <AssignmentBuilder store={store} actions={actions} pushToast={pushToast} c={c} onClose={() => setBuilding(false)} />}
      {feedbackFor && <SubmissionsModal store={store} actions={actions} pushToast={pushToast} assignment={store.assignments[feedbackFor]} onClose={() => setFeedbackFor(null)} />}
    </>
  );
}

function fmtDue(ymd) {
  if (!ymd) return "no date";
  const d = new Date(ymd + "T00:00:00");
  const today = new Date(); today.setHours(0, 0, 0, 0);
  const diff = Math.round((d - today) / 86400000);
  const str = d.toLocaleDateString(undefined, { month: "short", day: "numeric" });
  if (diff === 0) return `${str} · today`;
  if (diff === 1) return `${str} · tomorrow`;
  if (diff < 0) return `${str} · ${-diff}d ago`;
  return `${str} · in ${diff}d`;
}

function AssignmentBuilder({ store, actions, pushToast, c, onClose }) {
  // Scope every pickable source to THIS class's exam: an OGE class can only
  // assign OGE content (grammar + word-formation passages, no multiple-choice).
  const exam = c.exam || "ege";
  const examOf = (m) => (m.exam || "ege");
  const examFamilies = FAMILY_ORDER.filter(f => (exam === "oge" ? f !== "multiple-choice" : true));
  const examCats = Object.entries(CATEGORY_META).filter(([, m]) => examOf(m) === exam);
  const nOptions = exam === "oge" ? [3, 5, 10] : [5, 10, 20];   // OGE passages are long

  const [title, setTitle] = tUseState("");
  const [note, setNote] = tUseState("");
  const [kindType, setKindType] = tUseState("set");
  const [family, setFamily] = tUseState(examFamilies.includes("word-formation") ? "word-formation" : examFamilies[0]);
  const [n, setN] = tUseState(exam === "oge" ? 5 : 10);
  const [categoryId, setCategoryId] = tUseState((examCats[0] && examCats[0][0]) || "t1");
  const [taskId, setTaskId] = tUseState(Object.keys(store.tasks)[0] || "");
  const [assignAll, setAssignAll] = tUseState(true);
  const [selected, setSelected] = tUseState([]);
  const [due, setDue] = tUseState("");
  const [drillTypes, setDrillTypes] = tUseState({ complete: true, spelling: true, brackets: true });
  const [drillLen, setDrillLen] = tUseState(20);

  const drillTypeList = Object.keys(drillTypes).filter(t => drillTypes[t]);
  const kind = kindType === "set" ? { type: "set", family, n }
    : kindType === "test" ? { type: "test", categoryId }
    : kindType === "drill" ? { type: "drill", drill: "verbs", types: drillTypeList, len: String(drillLen) }
    : { type: "task", taskId };
  const targets = assignAll ? c.studentHandles : selected;
  const canPublish = title.trim().length >= 2 && targets.length > 0 && (kindType !== "task" || taskId) && (kindType !== "drill" || drillTypeList.length > 0);

  const publish = () => {
    actions.publishAssignment({ classroomId: c.id, title: title.trim(), note: note.trim(), kind, assignedTo: assignAll ? "all" : selected, dueDate: due || null });
    pushToast("Assignment published");
    onClose();
  };
  const toggleSel = (h) => setSelected(s => s.includes(h) ? s.filter(x => x !== h) : [...s, h]);

  return (
    <Modal title="New assignment" sub={c.name} onClose={onClose}
      foot={<>
        <div className="builder-summary">{targets.length} student{targets.length === 1 ? "" : "s"} · auto-scored</div>
        <button className="cta-primary" onClick={publish} disabled={!canPublish}><span>Publish</span><span className="cta-arrow">→</span></button>
      </>}>
      <div style={{ margin: "-18px -24px 0" }}>
        <div className="build-field">
          <div className="build-label">Title</div>
          <input className="field-input" autoFocus value={title} onChange={e => setTitle(e.target.value)} placeholder="e.g. Suffixes warm-up" maxLength={60} />
        </div>
        <div className="build-field">
          <div className="build-label">Note <span className="muted">(optional)</span></div>
          <textarea className="field-textarea" value={note} onChange={e => setNote(e.target.value)} placeholder="A short message for the class" maxLength={160} />
        </div>
        <div className="build-field">
          <div className="build-label">What to assign</div>
          <div className="kind-grid" style={{ marginBottom: 14 }}>
            {[["set", "A set", "N from a family"], ["test", "A file", "pick a source"], ["task", "My task", "one you wrote"], ["drill", "Focused drill", "irregular verbs"]].map(([v, t, s]) => (
              <button key={v} className={`kind-card ${kindType === v ? "is-on" : ""}`} onClick={() => setKindType(v)}>
                <span className="kind-card-t">{t}</span><span className="kind-card-s">{s}</span>
              </button>
            ))}
          </div>
          {kindType === "set" && (
            <div className="stack-sm" style={{ gap: 12 }}>
              <select className="field-select" value={family} onChange={e => setFamily(e.target.value)}>
                {examFamilies.map(f => <option key={f} value={f}>{FAMILY_META[f].label}</option>)}
              </select>
              <div className="segmented" role="radiogroup" aria-label="How many">
                {nOptions.map(v => <button key={v} className={`segmented-btn ${n === v ? "is-on" : ""}`} onClick={() => setN(v)}>{v}</button>)}
              </div>
            </div>
          )}
          {kindType === "test" && (() => {
            const fileCount = VOCAB.filter(v => v.category === categoryId).length;
            const fileMeta = CATEGORY_META[categoryId];
            return (
              <div className="stack-sm" style={{ gap: 8 }}>
                <select className="field-select" value={categoryId} onChange={e => setCategoryId(e.target.value)}>
                  {examFamilies.map(fam => (
                    <optgroup key={fam} label={FAMILY_META[fam].label}>
                      {examCats
                        .filter(([, m]) => m.family === fam)
                        .map(([id, m]) => <option key={id} value={id}>{m.label}</option>)}
                    </optgroup>
                  ))}
                </select>
                <p className="muted" style={{ margin: 0, fontSize: 13 }}>
                  {fileMeta?.blurb ? `${fileMeta.blurb} · ` : ""}{fileCount} item{fileCount === 1 ? "" : "s"} in this file
                  {fileCount > 20 ? " · 20 picked at random per student" : ""}
                </p>
              </div>
            );
          })()}
          {kindType === "task" && (
            Object.keys(store.tasks).length === 0
              ? <p className="muted" style={{ margin: 0 }}>You haven't written any tasks yet — see the My tasks tab.</p>
              : <select className="field-select" value={taskId} onChange={e => setTaskId(e.target.value)}>
                {Object.values(store.tasks).map(t => <option key={t.id} value={t.id}>{(t.sentence || t.text || "").replace(/_{2,}/g, "___").slice(0, 50)}…</option>)}
              </select>
          )}
          {kindType === "drill" && (
            <div className="stack-sm" style={{ gap: 12 }}>
              <p className="muted" style={{ fontSize: 13, margin: 0 }}>Irregular Verbs · choose the task types students get</p>
              <div className="kind-grid">
                {[["complete", "Complete the form"], ["spelling", "Spelling"], ["brackets", "Open the brackets"]].map(([v, t]) => (
                  <button key={v} className={`kind-card ${drillTypes[v] ? "is-on" : ""}`} onClick={() => setDrillTypes(s => { const next = { ...s, [v]: !s[v] }; return Object.values(next).some(Boolean) ? next : s; })}>
                    <span className="kind-card-t" style={{ fontSize: 13 }}>{t}</span>
                  </button>
                ))}
              </div>
              <div className="segmented" role="radiogroup" aria-label="Run length">
                {[10, 20, 30].map(v => <button key={v} className={`segmented-btn ${drillLen === v ? "is-on" : ""}`} onClick={() => setDrillLen(v)}>{v} questions</button>)}
              </div>
            </div>
          )}
        </div>
        <div className="build-field">
          <div className="build-label">Assign to</div>
          <div className="assignee-row" style={{ marginBottom: assignAll ? 0 : 12 }}>
            <button className={`student-pick ${assignAll ? "is-on" : ""}`} onClick={() => setAssignAll(true)}>Whole class · {c.studentHandles.length}</button>
            <button className={`student-pick ${!assignAll ? "is-on" : ""}`} onClick={() => setAssignAll(false)}>Selected students</button>
          </div>
          {!assignAll && (
            <div className="assignee-row">
              {c.studentHandles.map(h => {
                const p = store.directory[h];
                return <button key={h} className={`student-pick ${selected.includes(h) ? "is-on" : ""}`} onClick={() => toggleSel(h)}>
                  <Avatar name={p.name} hue={p.avatarHue} size="sm" />{p.name.split(" ")[0]}
                </button>;
              })}
            </div>
          )}
        </div>
        <div className="build-field">
          <div className="build-label">Due date <span className="muted">(optional)</span></div>
          <input type="date" className="field-input" value={due} onChange={e => setDue(e.target.value)} />
        </div>
      </div>
    </Modal>
  );
}

function SubmissionsModal({ store, actions, pushToast, assignment, onClose }) {
  const a = assignment;
  const entries = Object.entries(a.submissions);
  const [editing, setEditing] = tUseState(null);
  const [draft, setDraft] = tUseState("");
  const outstanding = entries.filter(([, s]) => s.status !== "completed");

  return (
    <Modal title={a.title} sub={`${assignmentLabel(a.kind)} · due ${fmtDue(a.dueDate)}`} onClose={onClose}
      foot={<>
        {outstanding.length > 0 && (
          <button className="cta-secondary" onClick={() => pushToast(`Reminded ${outstanding.length} student${outstanding.length === 1 ? "" : "s"}`)}>
            Remind {outstanding.length} outstanding
          </button>
        )}
        <button className="cta-secondary" onClick={onClose}>Done</button>
      </>}>
      <div style={{ margin: "-18px -24px 0" }}>
        {entries.map(([h, sub]) => {
          const p = store.directory[h];
          if (!p) return null;
          return (
            <div className="person-row" key={h} style={{ alignItems: "flex-start" }}>
              <Avatar name={p.name} hue={p.avatarHue} size="sm" />
              <div className="person-id">
                <div className="person-name">{p.name}</div>
                {sub.status === "completed"
                  ? <div className="person-handle">{sub.correct}/{sub.total} · {Math.round(sub.accuracy * 100)}%</div>
                  : <div style={{ marginTop: 4 }}><StatusPill status={sub.status} /></div>}
                {editing === h && (
                  <div className="stack-sm" style={{ marginTop: 8 }}>
                    <textarea className="field-textarea" value={draft} onChange={e => setDraft(e.target.value)} placeholder="Optional feedback note" autoFocus />
                    <div className="row-gap">
                      <button className="cta-secondary" onClick={() => setEditing(null)}>Cancel</button>
                      <button className="cta-primary" onClick={() => { actions.setFeedback(a.id, h, draft); pushToast("Note saved"); setEditing(null); }}><span>Save note</span><span className="cta-arrow">→</span></button>
                    </div>
                  </div>
                )}
                {editing !== h && sub.feedbackNote && <div className="muted" style={{ marginTop: 6, fontStyle: "italic" }}>“{sub.feedbackNote}”</div>}
              </div>
              {sub.status === "completed" && editing !== h && (
                <div style={{ display: "flex", gap: 12, alignItems: "center", flexShrink: 0 }}>
                  {sub.seen
                    ? <span style={{ fontSize: 12, fontWeight: 700, color: "var(--ok)" }}>Seen ✓</span>
                    : <button className="text-link" onClick={() => { actions.markSeen(a.id, h); pushToast(`Marked @${h} as seen`); }}>Mark seen</button>}
                  <button className="text-link" onClick={() => { setEditing(h); setDraft(sub.feedbackNote || ""); }}>{sub.feedbackNote ? "Edit" : "Add note"}</button>
                </div>
              )}
              {sub.status !== "completed" && (
                <button className="text-link" onClick={() => pushToast(`Reminder sent to @${h}`)}>Nudge</button>
              )}
            </div>
          );
        })}
      </div>
    </Modal>
  );
}

// ---------------------------------------------------------------------
// My tasks tab + task editor
// ---------------------------------------------------------------------
function MyTasksTab({ store, actions, pushToast }) {
  const [editing, setEditing] = tUseState(false);
  const tasks = Object.values(store.tasks);

  return (
    <>
      <div className="row-gap" style={{ justifyContent: "space-between", marginBottom: 14 }}>
        <div className="section-label" style={{ margin: 0 }}>{tasks.length} task{tasks.length === 1 ? "" : "s"} · auto-graded</div>
        <button className="cta-primary" onClick={() => setEditing(true)}><span>New task</span><span className="cta-arrow">+</span></button>
      </div>
      {tasks.length === 0 ? (
        <EmptyState icon="+" title="No tasks yet"
          cta={<button className="cta-primary" onClick={() => setEditing(true)}><span>Write your first task</span><span className="cta-arrow">+</span></button>}>
          Write items in the three exam formats — word formation, grammar gap-fill, multiple choice — with the correct answer, and they auto-grade like everything else.
        </EmptyState>
      ) : (
        <div className="panel">
          {tasks.map(t => (
            <div className="hw-row" key={t.id} style={{ cursor: "default" }}>
              <div className="hw-main">
                <div className="hw-eyebrow">
                  <span className="task-tag" data-task={t.type}>{FAMILY_META[t.type]?.label}</span>
                  <span className="badge">my task</span>
                  {t.base && <span className="mistake-base">{t.base}</span>}
                </div>
                <div className="hw-title">{(t.sentence || t.text || "").replace(/⟦\d+⟧/g, " ______ ").replace(/_{2,}/g, "______")}</div>
                <div className="hw-meta"><span>Answer <b style={{ color: "var(--accent-ink)" }}>{t.gaps ? t.gaps.map(g => g.answer).join(", ") : t.answer}</b></span></div>
              </div>
            </div>
          ))}
        </div>
      )}
      {editing && <TaskEditor actions={actions} pushToast={pushToast} onClose={() => setEditing(false)} />}
    </>
  );
}

function TaskEditor({ actions, pushToast, onClose, task }) {
  const editing = !!task;
  const [type, setType] = tUseState(task ? task.type : "word-formation");
  const [sentence, setSentence] = tUseState(task ? (task.sentence || "") : "");
  const [base, setBase] = tUseState(task ? (task.base || "") : "");
  const [answer, setAnswer] = tUseState(task && task.type !== "multiple-choice" ? (task.answer || "") : "");
  const initChoices = (task && task.type === "multiple-choice" && Array.isArray(task.choices))
    ? [0, 1, 2, 3].map(i => task.choices[i] || "") : ["", "", "", ""];
  const [choices, setChoices] = tUseState(initChoices);
  const [correctIdx, setCorrectIdx] = tUseState((task && task.type === "multiple-choice" && Array.isArray(task.choices))
    ? Math.max(0, task.choices.indexOf(task.answer)) : 0);
  const [exam, setExam] = tUseState(task && task.exam ? task.exam : "ege");
  const [note, setNote] = tUseState(task ? (task.note || "") : "");
  // OGE has no multiple-choice, so an MC task is always ЕГЭ.
  const examV = type === "multiple-choice" ? "ege" : exam;

  const hasBlank = /_{2,}|___/.test(sentence);
  const valid = sentence.trim().length > 4 && hasBlank &&
    (type === "multiple-choice"
      ? choices.filter(c => c.trim()).length >= 2 && choices[correctIdx]?.trim()
      : answer.trim() && (type === "grammar" || base.trim()));

  const save = () => {
    const payload = type === "multiple-choice"
      ? { type, sentence: sentence.trim(), choices: choices.map(c => c.trim()).filter(Boolean), answer: choices[correctIdx].trim(), alts: [], note: note.trim(), exam: examV }
      : { type, sentence: sentence.trim(), base: base.trim().toUpperCase(), answer: answer.trim(), alts: [], note: note.trim(), exam: examV };
    if (editing) actions.updateTask(task.id, payload); else actions.addTask(payload);
    pushToast(editing ? "Task updated" : "Task added");
    onClose();
  };

  const preview = sentence.replace(/_{2,}|___/, `\u00A0${type === "multiple-choice" ? (choices[correctIdx] || "____") : (answer || "____")}\u00A0`);

  return (
    <Modal title={editing ? "Edit task" : "Write a task"} sub="Auto-graded · flagged “my task”" onClose={onClose}
      foot={<>
        <button className="cta-secondary" onClick={onClose}>Cancel</button>
        <button className="cta-primary" onClick={save} disabled={!valid}><span>{editing ? "Save changes" : "Add task"}</span><span className="cta-arrow">→</span></button>
      </>}>
      <div style={{ margin: "-18px -24px 0" }}>
        <div className="build-field">
          <div className="build-label">Format</div>
          <div className="kind-grid">
            {[["word-formation", "Word formation"], ["grammar", "Grammar gap-fill"], ["multiple-choice", "Multiple choice"]].map(([v, t]) => (
              <button key={v} className={`kind-card ${type === v ? "is-on" : ""}`} onClick={() => setType(v)}><span className="kind-card-t">{t}</span></button>
            ))}
          </div>
        </div>
        <div className="build-field">
          <div className="build-label">Exam {type === "multiple-choice" ? <span className="muted">— ЕГЭ (ОГЭ has no multiple-choice)</span> : null}</div>
          <div className="segmented" role="radiogroup" aria-label="Exam">
            {[["ege", "ЕГЭ"], ["oge", "ОГЭ"]].map(([v, l]) => (
              <button key={v} className={`segmented-btn ${examV === v ? "is-on" : ""}`} disabled={type === "multiple-choice" && v === "oge"} onClick={() => setExam(v)}>{l}</button>
            ))}
          </div>
        </div>
        <div className="build-field">
          <div className="build-label">Sentence</div>
          <div className="build-hint">Use <b>___</b> (three underscores) where the blank goes.</div>
          <textarea className="field-textarea" autoFocus value={sentence} onChange={e => setSentence(e.target.value)} placeholder="The committee reached a unanimous ___ after a long debate." />
        </div>
        {type !== "multiple-choice" && (
          <>
            <div className="build-field">
              <div className="build-label">Base word (CAPS cue){type === "grammar" ? <span className="muted"> (optional)</span> : null}</div>
              <input className="field-input" value={base} onChange={e => setBase(e.target.value)} placeholder={type === "grammar" ? "GO" : "DECIDE"} />
            </div>
            <div className="build-field">
              <div className="build-label">Correct answer</div>
              <input className="field-input" value={answer} onChange={e => setAnswer(e.target.value)} placeholder={type === "grammar" ? "had gone" : "decision"} />
            </div>
          </>
        )}
        {type === "multiple-choice" && (
          <div className="build-field">
            <div className="build-label">Options <span className="muted">— tap the correct one</span></div>
            <div className="stack-sm">
              {choices.map((ch, i) => (
                <div className="row-gap" key={i} style={{ flexWrap: "nowrap" }}>
                  <button className={`choice-chip ${correctIdx === i ? "is-on" : ""}`} style={{ minWidth: 44 }} onClick={() => setCorrectIdx(i)} aria-label={`Mark option ${i + 1} correct`}>{correctIdx === i ? "✓" : String.fromCharCode(65 + i)}</button>
                  <input className="field-input grow" value={ch} onChange={e => setChoices(c => c.map((x, j) => j === i ? e.target.value : x))} placeholder={`option ${i + 1}`} />
                </div>
              ))}
            </div>
          </div>
        )}
        <div className="build-field">
          <div className="build-label">Note <span className="muted">(optional)</span></div>
          <input className="field-input" value={note} onChange={e => setNote(e.target.value)} placeholder="A short explanation students see after answering" maxLength={200} />
        </div>
        {hasBlank && (
          <div className="build-field">
            <div className="task-preview">
              <div className="task-preview-label">Preview · how students see it (answer revealed)</div>
              <div className="task-preview-sentence">{preview.split(/(\u00A0[^\u00A0]+\u00A0)/).map((part, i) => part.startsWith("\u00A0") ? <span className="blank-prev" key={i}>{part.trim()}</span> : part)}</div>
            </div>
          </div>
        )}
      </div>
    </Modal>
  );
}

// =====================================================================
// Teacher · My Tasks (top-level page) — the personal, reusable task bank
// =====================================================================
const T_PENCIL = (<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 20h4l10-10-4-4L4 16v4z" /><path d="M13.5 6.5l4 4" /></svg>);
const T_TRASH = (<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13" /></svg>);

function ExamPill({ exam }) {
  if (exam !== "oge" && exam !== "ege") return null;
  return <span className={`exam-pill ${exam === "oge" ? "is-oge" : "is-ege"}`}>{exam === "oge" ? "ОГЭ" : "ЕГЭ"}</span>;
}

function TeacherTaskCard({ t, onEdit, onDelete }) {
  const isMC = t.type === "multiple-choice";
  return (
    <div className="mt-card">
      <div className="mt-top">
        <span className="task-tag" data-task={t.type}>{FAMILY_META[t.type]?.label || t.type}</span>
        <ExamPill exam={t.exam} />
        {t.base ? <span className="mt-cue">{t.base}</span> : null}
        <div className="mt-acts">
          <button className="mt-icon" aria-label="Edit task" onClick={onEdit}>{T_PENCIL}</button>
          <button className="mt-icon" aria-label="Delete task" onClick={onDelete}>{T_TRASH}</button>
        </div>
      </div>
      <div className="mt-sentence">{(t.sentence || "").replace(/_{2,}|___/g, "______")}</div>
      {isMC ? (
        <>
          <div className="mt-mc">
            {(t.choices || []).map((c, i) => {
              const correct = c === t.answer;
              return (
                <div key={i} className={`mt-opt ${correct ? "is-correct" : ""}`}>
                  <span className="mt-opt-l">{String.fromCharCode(65 + i)}</span>
                  <span className="mt-opt-t">{c}</span>
                  {correct ? <span className="mt-opt-c">✓</span> : null}
                </div>
              );
            })}
          </div>
          {t.note ? <div className="mt-note">“{t.note}”</div> : null}
        </>
      ) : (
        <div className="mt-answer">Answer <b>{t.answer}</b>{t.alts && t.alts.length ? <span className="muted"> · also accepts {t.alts.join(", ")}</span> : null}</div>
      )}
    </div>
  );
}

function TeacherTasksScreen({ store, actions, pushToast, dataState, onBack }) {
  const [editing, setEditing] = tUseState(null);   // null | "new" | task
  const [fmt, setFmt] = tUseState("all");
  const [exam, setExam] = tUseState("all");
  const [confirmDel, setConfirmDel] = tUseState(null);

  const all = Object.values(store.tasks || {});
  const tasks = all.filter(t => (fmt === "all" || t.type === fmt) && (exam === "all" || (t.exam || "") === exam));

  return (
    <div className="mistakes-shell mt-shell">
      <header className="sub-header">
        <div className="sub-title">My tasks</div>
        <button className="cta-primary" onClick={() => setEditing("new")}><span>New task</span><span className="cta-arrow">+</span></button>
      </header>
      <p className="sub-lead">Your personal task bank — available across all your classes and in Live games. Write once, reuse anywhere.</p>

      <div className="mt-filters">
        <div className="mt-filter"><span className="mt-cap">Format</span>
          <div className="segmented">
            {[["all", "All"], ["word-formation", "Word form."], ["grammar", "Grammar"], ["multiple-choice", "MC"]].map(([v, l]) =>
              <button key={v} className={`segmented-btn ${fmt === v ? "is-on" : ""}`} onClick={() => setFmt(v)}>{l}</button>)}
          </div>
        </div>
        <div className="mt-filter"><span className="mt-cap">Exam</span>
          <div className="segmented">
            {[["all", "All"], ["oge", "ОГЭ"], ["ege", "ЕГЭ"]].map(([v, l]) =>
              <button key={v} className={`segmented-btn ${exam === v ? "is-on" : ""}`} onClick={() => setExam(v)}>{l}</button>)}
          </div>
        </div>
      </div>

      <div className="section-label" style={{ margin: "2px 0 14px" }}>{tasks.length} task{tasks.length === 1 ? "" : "s"} · auto-graded</div>

      {all.length === 0 ? (
        dataState !== "ready"
          ? <p className="muted">Loading your tasks…</p>
          : <EmptyState icon="+" title="No tasks yet"
              cta={<button className="cta-primary" onClick={() => setEditing("new")}><span>Write your first task</span><span className="cta-arrow">+</span></button>}>
              Write items in the three exam formats — word formation, grammar gap-fill, multiple choice — and reuse them in any class or Live game.
            </EmptyState>
      ) : tasks.length === 0 ? (
        <EmptyState icon="○" title="Nothing matches">No tasks in this filter — try a different format or exam.</EmptyState>
      ) : (
        <div className="mt-grid">
          {tasks.map(t => <TeacherTaskCard key={t.id} t={t} onEdit={() => setEditing(t)} onDelete={() => setConfirmDel(t)} />)}
        </div>
      )}

      {editing && <TaskEditor actions={actions} pushToast={pushToast} task={editing === "new" ? null : editing} onClose={() => setEditing(null)} />}
      {confirmDel && (
        <Modal title="Delete this task?" sub={(confirmDel.sentence || "").replace(/_{2,}|___/g, "____").slice(0, 60)} onClose={() => setConfirmDel(null)}
          foot={<>
            <button className="cta-secondary" onClick={() => setConfirmDel(null)}>Cancel</button>
            <button className="cta-primary" style={{ background: "var(--no)" }} onClick={() => { actions.deleteTask(confirmDel.id); pushToast("Task deleted"); setConfirmDel(null); }}><span>Delete</span><span className="cta-arrow">→</span></button>
          </>}>
          This permanently removes the task from your bank.
        </Modal>
      )}
    </div>
  );
}

// =====================================================================
// Teacher · My Students — everyone across every class, in one place
// =====================================================================
function shortClassName(name) { const n = String(name || ""); return n.length > 18 ? n.slice(0, 17) + "…" : n; }

function MyStudentsScreen({ store, actions, pushToast, dataState, onBack }) {
  const [q, setQ] = tUseState("");
  const [sort, setSort] = tUseState("name");   // name | active
  const [detail, setDetail] = tUseState(null);  // { handle, classId }
  const [pop, setPop] = tUseState(null);        // handle of the open per-class popover

  const myHandle = store.account && store.account.handle;
  const owned = Object.values(store.classrooms || {}).filter(c => c.ownerHandle === myHandle);
  const byHandle = {};
  for (const c of owned) {
    for (const h of (c.studentHandles || [])) {
      if (!byHandle[h]) byHandle[h] = { handle: h, classes: [] };
      const st = (c.memberStats && c.memberStats[h]) || {};
      byHandle[h].classes.push({ id: c.id, name: c.name, exam: c.exam || "ege", accuracy: st.accuracy || 0, score: st.totalScore || 0, answered: st.answered || 0 });
    }
  }
  let students = Object.values(byHandle).map(s => {
    const p = store.directory[s.handle] || { name: "@" + s.handle, avatarHue: 0 };
    return { ...s, name: p.name || ("@" + s.handle), avatarHue: p.avatarHue || 0, lastSeenDaysAgo: p.lastSeenDaysAgo };
  });
  const term = q.trim().toLowerCase();
  if (term) students = students.filter(s => (s.name || "").toLowerCase().includes(term) || s.handle.toLowerCase().includes(term));
  students.sort((a, b) => sort === "active"
    ? (((a.lastSeenDaysAgo == null ? 9999 : a.lastSeenDaysAgo) - (b.lastSeenDaysAgo == null ? 9999 : b.lastSeenDaysAgo)) || a.name.localeCompare(b.name))
    : a.name.localeCompare(b.name));

  if (detail) {
    return <StudentDetail store={store} actions={actions} pushToast={pushToast} handle={detail.handle} classId={detail.classId} onBack={() => setDetail(null)} />;
  }

  const open = (s) => {
    if (s.classes.length === 1) setDetail({ handle: s.handle, classId: s.classes[0].id });
    else setPop(pop === s.handle ? null : s.handle);
  };

  return (
    <div className="mistakes-shell st-shell">
      <header className="sub-header"><div className="sub-title">Students</div></header>
      <p className="sub-lead">{students.length} student{students.length === 1 ? "" : "s"} · {owned.length} class{owned.length === 1 ? "" : "es"} — everyone across all your classes in one place.</p>

      <div className="st-controls">
        <div className="st-search">
          <span className="st-search-ic" aria-hidden="true">⌕</span>
          <input className="field-input" value={q} onChange={e => setQ(e.target.value)} placeholder="Search students" />
        </div>
        <div className="segmented">
          {[["name", "Name"], ["active", "Last active"]].map(([v, l]) =>
            <button key={v} className={`segmented-btn ${sort === v ? "is-on" : ""}`} onClick={() => setSort(v)}>{l}</button>)}
        </div>
      </div>

      {dataState !== "ready" && owned.length === 0 ? (
        <p className="muted">Loading your classes…</p>
      ) : owned.length === 0 ? (
        <EmptyState icon="○" title="No classes yet">Create a class and invite students from the Class tab — they'll all show up here.</EmptyState>
      ) : students.length === 0 ? (
        <EmptyState icon="○" title="No students">No students match. Invite students from a class roster.</EmptyState>
      ) : (
        <div className="st-list">
          {students.map(s => (
            <div key={s.handle} className="st-row" onClick={() => open(s)} role="button" tabIndex={0}>
              <Avatar name={s.name} hue={s.avatarHue} size="md" />
              <div className="st-id">
                <div className="st-name">{s.name} <span className="st-handle">@{s.handle}</span></div>
                <div className="st-chips">
                  {s.classes.map(c => <span key={c.id} className={`st-chip ${c.exam === "oge" ? "is-oge" : "is-ege"}`}>{shortClassName(c.name)} · {c.exam === "oge" ? "ОГЭ" : "ЕГЭ"}</span>)}
                </div>
              </div>
              <div className="st-meta">
                <div className={`st-active ${s.lastSeenDaysAgo === 0 ? "is-today" : ""}`}>{seenLabel(s.lastSeenDaysAgo)}</div>
                <div className="st-more">{s.classes.length > 1 ? `${s.classes.length} classes ` : ""}›</div>
              </div>
              {pop === s.handle && (
                <div className="st-pop" onClick={(e) => e.stopPropagation()}>
                  <div className="st-pop-head">{s.name}<span className="st-pop-sub">@{s.handle} · {s.classes.length} classes · stats tracked separately per exam</span></div>
                  {s.classes.map(c => (
                    <button key={c.id} className="st-pop-row" onClick={() => { setPop(null); setDetail({ handle: s.handle, classId: c.id }); }}>
                      <div className="st-pop-cls">{c.name}<span className={`st-chip ${c.exam === "oge" ? "is-oge" : "is-ege"}`}>{c.exam === "oge" ? "ОГЭ" : "ЕГЭ"}</span></div>
                      <div className="st-pop-stat"><b>{Math.round((c.accuracy || 0) * 100)}%</b><span>accuracy</span></div>
                      <div className="st-pop-stat"><b>{c.score || 0}</b><span>points</span></div>
                      <span className="st-pop-arrow">›</span>
                    </button>
                  ))}
                </div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { TeacherClass, TeacherTasksScreen, MyStudentsScreen });
