/* ==================================================================
   Doubts — Student↔Teacher per-question threads
   ------------------------------------------------------------------
   Left column: list of doubts the calling user can see (test author +
   HoD/admin for the owning school). Tabs filter by status.
   Right column: selected thread — original question, what the student
   picked, the message timeline, and a reply composer (text + image).

   The bell in shell.jsx surfaces 'doubt_raised' / 'doubt_message'
   notifications; clicking one navigates here with the doubt preselected
   (via window.APP.DOUBTS_CONTEXT seeded by app.jsx).
   ================================================================== */

const { Icon: DbIcon } = window.AppUI;

const STATUS_LABEL = { open: "Open", answered: "Replied", resolved: "Resolved" };
const STATUS_CLS   = { open: "amber", answered: "blue", resolved: "green" };

const relTimeD = (iso) => {
  if (!iso) return "";
  const ms = Date.now() - new Date(iso).getTime();
  const s = Math.floor(ms / 1000);
  if (s < 60) return `${s}s ago`;
  if (s < 3600) return `${Math.floor(s/60)}m ago`;
  if (s < 86400) return `${Math.floor(s/3600)}h ago`;
  return `${Math.floor(s/86400)}d ago`;
};

const DoubtsScreen = () => {
  const [items, setItems] = React.useState([]);
  const [counts, setCounts] = React.useState({ open: 0, answered: 0, resolved: 0 });
  const [tab, setTab] = React.useState("open");
  const [selectedId, setSelectedId] = React.useState(() => window.APP?.DOUBTS_CONTEXT?.doubtId || null);
  const [search, setSearch] = React.useState("");
  const [loading, setLoading] = React.useState(true);
  const [err, setErr] = React.useState(null);

  const refresh = React.useCallback(async () => {
    setLoading(true); setErr(null);
    try {
      const [list, c] = await Promise.all([
        window.AppApi.get(`/teacher/doubts${tab === "all" ? "" : `?status=${tab}`}`),
        window.AppApi.get("/teacher/doubts/counts"),
      ]);
      setItems(list || []);
      setCounts(c || { open: 0, answered: 0, resolved: 0 });
    } catch (e) {
      setErr(String(e.message || e));
    } finally { setLoading(false); }
  }, [tab]);

  React.useEffect(() => { refresh(); }, [refresh]);

  // Clear the cross-screen context once we've consumed it. The selectedId
  // is now state-owned so the user can navigate freely from here.
  React.useEffect(() => {
    if (window.APP?.DOUBTS_CONTEXT) {
      // If the context's doubt belongs to a different status tab, switch.
      const ctx = window.APP.DOUBTS_CONTEXT;
      if (ctx.tab && ctx.tab !== tab) setTab(ctx.tab);
      delete window.APP.DOUBTS_CONTEXT;
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  const filtered = items.filter((d) => {
    if (!search) return true;
    const q = search.toLowerCase();
    return (
      (d.studentName || "").toLowerCase().includes(q) ||
      (d.studentRoll || "").toLowerCase().includes(q) ||
      (d.testTitle || "").toLowerCase().includes(q) ||
      (d.testDisplayId || "").toLowerCase().includes(q) ||
      (d.qTextPreview || "").toLowerCase().includes(q)
    );
  });

  const selected = filtered.find((d) => d.id === selectedId)
                || items.find((d) => d.id === selectedId)
                || null;

  return (
    <div style={{ display: "grid", gridTemplateColumns: "minmax(360px, 460px) 1fr", height: "100%", overflow: "hidden" }}>
      {/* ─── Left: list ─── */}
      <div style={{ overflow: "auto", padding: "28px 24px", borderRight: "1px solid var(--line)", background: "var(--bg-1)" }}>
        <div className="cx-eyebrow" style={{ marginBottom: 6 }}>Student doubts</div>
        <h1 className="cx-h1">Conversations</h1>
        <p className="muted" style={{ margin: "6px 0 0", fontSize: 13, lineHeight: 1.5, maxWidth: 480 }}>
          Threads opened by students from the report screen. You see threads on tests you authored; HoDs and admins see the whole school.
        </p>

        {/* Tabs */}
        <div style={{ marginTop: 18 }}>
          <window.AppUI.Tabs value={tab} onChange={setTab} full ariaLabel="Doubt status"
            items={["open", "answered", "resolved"].map((t) => ({ value: t, label: STATUS_LABEL[t], count: counts[t] || 0 }))}/>
        </div>

        {/* Search */}
        <div className="ui-search" style={{ marginTop: 12 }}>
          <DbIcon name="search" size={14}/>
          <input className="input" type="text" value={search} onChange={(e) => setSearch(e.target.value)}
            placeholder="Search student, test, question…" style={{ width: "100%" }}/>
        </div>

        {err && <div className="ui-alert red" style={{ marginTop: 14 }}>{err}</div>}
        {loading && <div className="muted" style={{ marginTop: 16, fontSize: 13 }}>Loading…</div>}

        <div style={{ marginTop: 14, display: "flex", flexDirection: "column", gap: 8 }}>
          {!loading && filtered.length === 0 && (
            <window.AppUI.EmptyState icon="inbox" title={`No ${STATUS_LABEL[tab].toLowerCase()} doubts`} compact card/>
          )}
          {filtered.map((d) => {
            const active = d.id === selectedId;
            return (
              <button key={d.id} onClick={() => setSelectedId(d.id)}
                style={{
                  textAlign: "left", padding: "12px 14px", font: "inherit",
                  background: active ? "var(--surface-active)" : "var(--surface)",
                  border: `1px solid ${active ? "var(--line-strong)" : "var(--line)"}`,
                  borderRadius: "var(--radius-tile)", cursor: "pointer", display: "flex", gap: 12,
                }}>
                <window.AppUI.Avatar name={d.studentName} size="sm"/>
                <div style={{ minWidth: 0, flex: 1, display: "flex", flexDirection: "column", gap: 4 }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                    <span style={{ color: "var(--ink-0)", fontSize: 13.5, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{d.studentName}</span>
                    <span className="ui-id">{d.studentRoll}</span>
                    <span style={{ color: "var(--ink-3)", fontSize: 11.5, marginLeft: "auto", whiteSpace: "nowrap" }}>{relTimeD(d.lastAt || d.updatedAt)}</span>
                  </div>
                  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                    <window.AppUI.StatusBadge tone={STATUS_CLS[d.status]}>{STATUS_LABEL[d.status]}</window.AppUI.StatusBadge>
                    <span className="ui-id">{d.testDisplayId} · Q{d.qNo}</span>
                  </div>
                  <div className="muted" style={{ fontSize: 12.5, lineHeight: 1.4,
                    overflow: "hidden", textOverflow: "ellipsis", display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical" }}>
                    {d.lastSender === "teacher" ? "↪ " : ""}{d.lastBody || d.qTextPreview}
                  </div>
                </div>
              </button>
            );
          })}
        </div>
      </div>

      {/* ─── Right: detail ─── */}
      {selected ? (
        <DoubtDetail key={selected.id} doubtId={selected.id} onRefresh={refresh}/>
      ) : (
        <div style={{ display: "grid", placeItems: "center" }}>
          <window.AppUI.EmptyState icon="message" title="No thread selected" hint="Select a doubt to read and reply."/>
        </div>
      )}
    </div>
  );
};

// Render any $…$ / \(…\) / \[…\] math inside a container after React has
// flushed. KaTeX's auto-render lib is loaded via index.html. We swallow
// failures so an unsupported delimiter doesn't tear down the screen.
const KATEX_DELIMS = [
  { left: "$$", right: "$$", display: true },
  { left: "\\[", right: "\\]", display: true },
  { left: "$",  right: "$",   display: false },
  { left: "\\(", right: "\\)", display: false },
];
const renderMathIn = (el) => {
  if (!el || typeof window.renderMathInElement !== "function") return;
  try {
    window.renderMathInElement(el, {
      delimiters: KATEX_DELIMS,
      throwOnError: false,
      ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code", "input"],
    });
  } catch {}
};

const DoubtDetail = ({ doubtId, onRefresh }) => {
  const [thread, setThread] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [err, setErr] = React.useState(null);
  const [draft, setDraft] = React.useState("");
  const [pending, setPending] = React.useState([]); // [{ kind, url, filename, mime, size }]
  const [uploading, setUploading] = React.useState(false);
  const [sending, setSending] = React.useState(false);
  const fileRef = React.useRef(null);
  const scrollRef = React.useRef(null);
  const mathRootRef = React.useRef(null);

  const load = React.useCallback(async () => {
    setLoading(true); setErr(null);
    try {
      const data = await window.AppApi.get(`/teacher/doubts/${doubtId}`);
      setThread(data);
    } catch (e) {
      setErr(String(e.message || e));
    } finally { setLoading(false); }
  }, [doubtId]);

  React.useEffect(() => { load(); }, [load]);

  // Scroll to the latest message whenever the thread updates.
  React.useEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [thread?.messages?.length]);

  // After the thread renders (or its message count grows), pass over the
  // question card + message bodies so KaTeX replaces inline TeX.
  React.useEffect(() => {
    if (thread) renderMathIn(mathRootRef.current);
  }, [thread?.doubt?.id, thread?.messages?.length]);

  const upload = async (file) => {
    if (!file) return;
    setUploading(true); setErr(null);
    try {
      const form = new FormData();
      form.append("file", file);
      const token = window.AppApi.getToken();
      const r = await fetch(window.AppApi.base + "/teacher/doubts/upload-attachment", {
        method: "POST",
        headers: token ? { authorization: `Bearer ${token}` } : {},
        body: form,
      });
      if (!r.ok) throw new Error(`upload ${r.status}`);
      const att = await r.json();
      setPending((xs) => [...xs, att]);
    } catch (e) {
      setErr(String(e.message || e));
    } finally {
      setUploading(false);
      if (fileRef.current) fileRef.current.value = "";
    }
  };

  const send = async () => {
    const body = draft.trim();
    if (!body && pending.length === 0) return;
    setSending(true); setErr(null);
    try {
      await window.AppApi.post(`/teacher/doubts/${doubtId}/messages`, { body, attachments: pending });
      setDraft(""); setPending([]);
      await load();
      onRefresh?.();
    } catch (e) {
      setErr(String(e.message || e));
    } finally { setSending(false); }
  };

  const resolve = async () => {
    if (!window.confirm("Mark this doubt as resolved? The student is notified.")) return;
    try {
      await window.AppApi.post(`/teacher/doubts/${doubtId}/resolve`, {});
      await load();
      onRefresh?.();
    } catch (e) { setErr(String(e.message || e)); }
  };

  if (loading) return <div className="muted" style={{ padding: 24 }}>Loading…</div>;
  if (err) return <div style={{ padding: 24, color: "var(--red)", fontSize: 13 }}>{err}</div>;
  if (!thread) return null;

  const d = thread.doubt;
  const q = thread.question;
  const sr = thread.studentResponse;
  const picked = q && sr?.selectedOptionId ? q.options.find((o) => o.id === sr.selectedOptionId) : null;

  return (
    <div style={{ display: "flex", flexDirection: "column", height: "100%", overflow: "hidden", background: "var(--bg-0)" }}>
      {/* Header */}
      <div style={{ padding: "18px 28px", borderBottom: "1px solid var(--line)", display: "flex", alignItems: "center", gap: 14 }}>
        <window.AppUI.Avatar name={d.studentName} size="lg"/>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div className="ui-pagehead-titlerow">
            <span style={{ fontSize: 18, fontWeight: 600, color: "var(--ink-0)", letterSpacing: "-0.2px" }}>{d.testTitle}</span>
            <window.AppUI.StatusBadge tone={STATUS_CLS[d.status]} variant="outline">{STATUS_LABEL[d.status]}</window.AppUI.StatusBadge>
          </div>
          <div className="ui-pagehead-meta" style={{ marginTop: 4 }}>
            <span className="ui-id">{d.testDisplayId} · Q{d.qNo}</span>
            <span>{d.studentName} <span className="ui-id">{d.studentRoll}</span></span>
            <span>opened {relTimeD(d.createdAt)}</span>
          </div>
        </div>
        {d.status !== "resolved" && (
          <button className="btn" onClick={resolve} title="Mark resolved">
            <DbIcon name="checkCircle" size={15}/>Mark resolved
          </button>
        )}
      </div>

      {/* Math-renderable region: question card + message bodies. */}
      <div ref={mathRootRef} style={{ display: "contents" }}>

      {/* Question card */}
      {q && (
        <div style={{ padding: "16px 28px", borderBottom: "1px solid var(--line)", background: "var(--bg-1)" }}>
          <div className="ui-section-label" style={{ marginBottom: 6 }}>
            Question · {q.marks} mark{q.marks === 1 ? "" : "s"}
          </div>
          <div style={{ color: "var(--ink-0)", fontSize: 14, lineHeight: 1.55, marginBottom: 10 }}>
            {q.text}
          </div>
          {q.options.length > 0 && (
            <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
              {q.options.map((o) => {
                const isCorrect = o.is_correct;
                const isPicked = picked?.id === o.id;
                return (
                  <div key={o.id} style={{
                    padding: "7px 12px", borderRadius: "var(--radius-ctl)", fontSize: 13,
                    display: "flex", alignItems: "center", gap: 8,
                    border: `1px solid ${isCorrect ? "color-mix(in srgb, var(--green-solid) 45%, transparent)" : isPicked ? "color-mix(in srgb, var(--red-solid) 45%, transparent)" : "var(--line)"}`,
                    background: isCorrect ? "var(--green-bg)" : isPicked ? "var(--red-bg)" : "var(--surface)",
                    color: "var(--ink-1)",
                  }}>
                    <span className="mono" style={{ color: "var(--ink-3)" }}>{o.letter}.</span>
                    <span style={{ flex: 1, minWidth: 0 }}>{o.text}</span>
                    {isCorrect && <window.AppUI.StatusBadge tone="green" icon="check">{isPicked ? "Correct · picked" : "Correct"}</window.AppUI.StatusBadge>}
                    {isPicked && !isCorrect && <window.AppUI.StatusBadge tone="red" icon="x">Student picked</window.AppUI.StatusBadge>}
                  </div>
                );
              })}
            </div>
          )}
          {q.expected_answer && (
            <details style={{ marginTop: 10 }}>
              <summary style={{ cursor: "pointer", fontSize: 12.5, color: "var(--ink-2)" }}>Show stored solution</summary>
              <div className="cx-note" style={{ marginTop: 8, fontSize: 13, color: "var(--ink-1)", lineHeight: 1.55, whiteSpace: "pre-wrap" }}>
                {q.expected_answer}
              </div>
            </details>
          )}
        </div>
      )}

      {/* Messages */}
      <div ref={scrollRef} style={{ flex: 1, overflowY: "auto", padding: "20px 28px", display: "flex", flexDirection: "column", gap: 12 }}>
        {thread.messages.length === 0 && (
          <window.AppUI.EmptyState icon="message" title="No messages yet" compact/>
        )}
        {thread.messages.map((m) => {
          const isTeacher = m.senderType === "teacher";
          const who = isTeacher ? (m.senderName || "Teacher") : (m.senderName || d.studentName);
          return (
            <div key={m.id} style={{ display: "flex", gap: 10, flexDirection: isTeacher ? "row-reverse" : "row", alignItems: "flex-end" }}>
              <window.AppUI.Avatar name={who} size="sm"/>
              <div style={{
                maxWidth: "70%", padding: "10px 14px", borderRadius: "var(--radius-tile)",
                background: isTeacher ? "var(--accent-bg)" : "var(--surface)",
                border: `1px solid ${isTeacher ? "color-mix(in srgb, var(--accent) 25%, transparent)" : "var(--line)"}`,
              }}>
                <div style={{ display: "flex", alignItems: "baseline", gap: 8, marginBottom: 3 }}>
                  <span style={{ fontSize: 12.5, fontWeight: 600, color: "var(--ink-1)" }}>{who}</span>
                  <span style={{ fontSize: 11.5, color: "var(--ink-3)" }}>{relTimeD(m.createdAt)}</span>
                </div>
                {m.body && <div style={{ fontSize: 13.5, color: "var(--ink-0)", whiteSpace: "pre-wrap", lineHeight: 1.5 }}>{m.body}</div>}
                {m.attachments?.length > 0 && (
                  <div style={{ marginTop: 8, display: "flex", flexWrap: "wrap", gap: 6 }}>
                    {m.attachments.map((a, i) =>
                      a.kind === "image" ? (
                        <a key={i} href={a.url} target="_blank" rel="noreferrer">
                          <img src={a.url} alt={a.filename || ""} style={{ maxHeight: 160, borderRadius: "var(--radius-ctl)", border: "1px solid var(--line)" }}/>
                        </a>
                      ) : null
                    )}
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>

      </div>
      {/* End math-renderable region */}

      {/* Composer */}
      {d.status !== "resolved" ? (
        <div style={{ padding: "14px 28px", borderTop: "1px solid var(--line)", background: "var(--bg-1)" }}>
          {pending.length > 0 && (
            <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: 10 }}>
              {pending.map((a, i) => (
                <div key={i} style={{ position: "relative" }}>
                  <img src={a.url} style={{ height: 48, width: 48, objectFit: "cover", borderRadius: "var(--radius-ctl)", border: "1px solid var(--line)" }}/>
                  <button className="ui-iconbtn sm" aria-label="Remove attachment"
                    onClick={() => setPending((xs) => xs.filter((_, j) => j !== i))}
                    style={{ position: "absolute", top: -8, right: -8, width: 20, height: 20, minWidth: 20, background: "var(--surface)", border: "1px solid var(--line)" }}>
                    <DbIcon name="x" size={11}/>
                  </button>
                </div>
              ))}
            </div>
          )}
          <div style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
            <textarea className="textarea" value={draft} onChange={(e) => setDraft(e.target.value)}
              placeholder="Type your reply…" rows={2}
              style={{ flex: 1, resize: "none", minHeight: 56 }}/>
            <input ref={fileRef} type="file" accept="image/*" style={{ display: "none" }}
              onChange={(e) => upload(e.target.files?.[0])}/>
            <button className="btn icon-only" onClick={() => fileRef.current?.click()} disabled={uploading || sending} title="Attach image" aria-label="Attach image">
              {uploading ? "…" : <DbIcon name="upload" size={15}/>}
            </button>
            <button className="btn primary" onClick={send} disabled={sending || (!draft.trim() && pending.length === 0)}>
              <DbIcon name="arrowUpRight" size={15}/>{sending ? "Sending…" : "Send reply"}
            </button>
          </div>
          {err && <div className="ui-alert red" style={{ marginTop: 8 }}>{err}</div>}
        </div>
      ) : (
        <div style={{ padding: "14px 28px", borderTop: "1px solid var(--line)", color: "var(--ink-3)", fontSize: 13, display: "flex", alignItems: "center", gap: 8 }}>
          <DbIcon name="checkCircle" size={15}/>
          This doubt is resolved. Re-open by asking the student to follow up from their report.
        </div>
      )}
    </div>
  );
};

window.DoubtsScreen = DoubtsScreen;
