/* =========================================================================
   Unified Notifications panel.
   ---------------------------------------------------------------------------
   A full, filterable history of the signed-in user's notifications — the same
   feed the topbar bell summarizes, but paged and filterable by Type and Date.
   Reads GET /api/notifications/feed?from&to&kind&limit&offset (per-user
   visibility, school timezone date filtering). Admins additionally see the
   admin-targeted kinds (e.g. an outside-schedule class logged by a teacher).
   ========================================================================= */
(function () {
  // Type filter options. Keep in sync with NotificationKind on the server;
  // unknown kinds still render via the fallback in `meta()`.
  const KIND_OPTIONS = [
    { value: "",                              label: "All types" },
    { value: "progress_extra_logged",         label: "Outside-schedule class" },
    { value: "attempt_submitted",             label: "Submission" },
    { value: "question_reported",             label: "Reported question" },
    { value: "doubt_raised",                  label: "Doubt raised" },
    { value: "doubt_message",                 label: "Doubt follow-up" },
    { value: "retest_requested",              label: "Retest request" },
    { value: "chat_report_raised",            label: "Chat report" },
    { value: "kinetix_access_request_raised", label: "KinetiX access request" },
    { value: "attendance_checkout_override",  label: "Off-site check-out" },
    { value: "teacher_registration_pending",  label: "New staff registration" },
    { value: "parent_registration_pending",   label: "New parent registration" },
    { value: "password_reset_requested",      label: "Password reset request" },
    { value: "form_submission_received",      label: "Form application" },
  ];
  const KIND_LABEL = Object.fromEntries(KIND_OPTIONS.map(o => [o.value, o.label]));

  const relTime = (iso) => {
    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 fmtAbs = (iso) => {
    try {
      return new Date(iso).toLocaleString(undefined, {
        day: "2-digit", month: "short", hour: "numeric", minute: "2-digit",
      });
    } catch { return iso; }
  };

  // Per-kind pill colour + title/sub strings. Delegates to the single
  // renderer in shell.jsx so this screen and the topbar bell can never drift
  // — they did, and the bell was the one showing "undefined" for the most
  // common notification kind in the database.
  function meta(n) {
    return window.KXUI.notificationMeta(n);
  }

  function NotificationsScreen() {
    const { useState, useEffect } = React;
    const PAGE = 50;

    const [items, setItems]   = useState([]);
    const [loading, setLoad]  = useState(true);
    const [err, setErr]       = useState(null);
    const [hasMore, setMore]  = useState(false);
    const [offset, setOffset] = useState(0);

    // Filters
    const [kind, setKind] = useState("");
    const [from, setFrom] = useState("");
    const [to, setTo]     = useState("");

    const buildQuery = (off) => {
      const q = new URLSearchParams();
      if (kind) q.set("kind", kind);
      if (from) q.set("from", from);
      if (to)   q.set("to", to);
      q.set("limit", String(PAGE));
      q.set("offset", String(off));
      return q.toString();
    };

    const fetchPage = async (off, replace) => {
      setLoad(true); setErr(null);
      try {
        const data = await window.KXApi.get(`/notifications/feed?${buildQuery(off)}`);
        const rows = data?.items || [];
        setItems(prev => replace ? rows : [...prev, ...rows]);
        setMore(!!data?.has_more);
        setOffset(off + rows.length);
      } catch (e) {
        setErr(e?.message || "Failed to load notifications");
      } finally { setLoad(false); }
    };

    // Refetch from the top whenever a filter changes.
    useEffect(() => { fetchPage(0, true); /* eslint-disable-next-line */ }, [kind, from, to]);

    const markRead = async (id) => {
      try { await window.KXApi.post(`/notifications/${id}/read`, {}); } catch (_e) { /* best-effort */ }
      setItems(xs => xs.map(x => x.id === id ? { ...x, read_at: new Date().toISOString() } : x));
    };
    const markAll = async () => {
      try { await window.KXApi.post(`/notifications/read-all`, {}); } catch (_e) { /* best-effort */ }
      setItems(xs => xs.map(x => x.read_at ? x : { ...x, read_at: new Date().toISOString() }));
    };
    const clearFilters = () => { setKind(""); setFrom(""); setTo(""); };

    const hasFilters = kind || from || to;

    return (
      <div style={{ padding: 18 }}>
        {/* Filters */}
        <div className="card">
          <div className="card-head" style={{ gap: 10 }}>
            <span className="card-title">Notifications</span>
            <button className="btn ghost sm" onClick={() => fetchPage(0, true)} disabled={loading} style={{ marginLeft: "auto" }}>
              Refresh
            </button>
            <button className="btn ghost sm" onClick={markAll}>Mark all read</button>
          </div>
          <div className="card-body" style={{ padding: 16, display: "flex", flexWrap: "wrap", gap: 12, alignItems: "flex-end" }}>
            <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              <span style={{ color: "var(--ink-3)", fontSize: 10, textTransform: "uppercase", letterSpacing: ".04em" }}>Type</span>
              <select className="input" value={kind} onChange={e => setKind(e.target.value)} style={{ minWidth: 200 }}>
                {KIND_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
              </select>
            </label>
            <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              <span style={{ color: "var(--ink-3)", fontSize: 10, textTransform: "uppercase", letterSpacing: ".04em" }}>From</span>
              <input className="input" type="date" value={from} onChange={e => setFrom(e.target.value)} max={to || undefined}/>
            </label>
            <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
              <span style={{ color: "var(--ink-3)", fontSize: 10, textTransform: "uppercase", letterSpacing: ".04em" }}>To</span>
              <input className="input" type="date" value={to} onChange={e => setTo(e.target.value)} min={from || undefined}/>
            </label>
            {hasFilters && (
              <button className="btn ghost sm" onClick={clearFilters} style={{ marginBottom: 1 }}>Clear filters</button>
            )}
          </div>
        </div>

        {/* List */}
        <div className="card" style={{ marginTop: 16 }}>
          <div className="card-body" style={{ padding: 0 }}>
            {err && (
              <div style={{ padding: 16, color: "var(--red)", fontSize: 12 }}>{err}</div>
            )}
            {!err && items.length === 0 && (
              <div style={{ padding: 32, textAlign: "center", color: "var(--ink-3)", fontSize: 12 }}>
                {loading ? "Loading…" : hasFilters ? "No notifications match these filters." : "No notifications yet."}
              </div>
            )}

            {items.map(n => {
              const m = meta(n);
              const p = n.payload || {};
              const photo = n.kind === "progress_extra_logged" && p.photo_path
                ? `/api/progress-photos/${p.photo_path}` : null;
              return (
                <div key={n.id} onClick={() => { if (!n.read_at) markRead(n.id); }}
                  style={{
                    display: "flex", gap: 12, padding: "12px 16px",
                    borderBottom: "1px solid var(--line-soft)",
                    background: n.read_at ? "transparent" : "rgba(255,186,90,0.04)",
                    cursor: n.read_at ? "default" : "pointer",
                  }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 3 }}>
                      {!n.read_at && <span style={{ width: 6, height: 6, borderRadius: "50%", background: "var(--accent)", display: "inline-block" }}/>}
                      <span className={`pill ${m.pill}`} style={{ fontSize: 9 }}>{m.label}</span>
                      <span style={{ color: "var(--ink-3)", fontSize: 10, marginLeft: "auto" }} title={fmtAbs(n.created_at)}>
                        {fmtAbs(n.created_at)} · {relTime(n.created_at)}
                      </span>
                    </div>
                    <div style={{ color: "var(--ink-0)", fontSize: 13, marginBottom: 2 }}>{m.title}</div>
                    {m.sub && <div style={{ color: "var(--ink-2)", fontSize: 12, whiteSpace: "pre-wrap", wordBreak: "break-word" }}>{m.sub}</div>}
                  </div>
                  {photo && (
                    <a href={photo} target="_blank" rel="noreferrer" onClick={e => e.stopPropagation()} style={{ flexShrink: 0 }}>
                      <img src={photo} alt="Classroom evidence"
                        style={{ width: 84, height: 56, objectFit: "cover", borderRadius: 6, border: "1px solid var(--line)" }}/>
                    </a>
                  )}
                </div>
              );
            })}

            {hasMore && (
              <div style={{ padding: 12, textAlign: "center" }}>
                <button className="btn ghost sm" onClick={() => fetchPage(offset, false)} disabled={loading}>
                  {loading ? "Loading…" : "Load more"}
                </button>
              </div>
            )}
          </div>
        </div>
      </div>
    );
  }

  window.NotificationsScreen = NotificationsScreen;
})();
