/* =========================================================================
   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: "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" },
  ];
  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.AppUI.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.AppApi.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.AppApi.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.AppApi.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;

    const NIcon = window.AppUI.Icon;
    const unread = items.filter(x => !x.read_at).length;
    return (
      <div className="cx-page" style={{ maxWidth: 1100 }}>
        <window.AppUI.PageHeader
          eyebrow="Inbox"
          title="Notifications"
          status={unread > 0 ? <window.AppUI.StatusBadge tone="amber" variant="outline">{unread} unread</window.AppUI.StatusBadge> : null}
          meta={["Your full notification history, filterable by type and date."]}
          actions={<>
            <button className="btn" onClick={() => fetchPage(0, true)} disabled={loading}>
              <NIcon name="refresh" size={15}/>Refresh
            </button>
            <button className="btn" onClick={markAll}>
              <NIcon name="check" size={15}/>Mark all read
            </button>
          </>}
        />

        {/* Filters */}
        <div className="cx-card tight" style={{ display: "flex", flexWrap: "wrap", gap: 12, alignItems: "flex-end" }}>
          <div className="field" style={{ margin: 0 }}>
            <label className="label">Type</label>
            <select className="select" value={kind} onChange={e => setKind(e.target.value)} style={{ width: 240 }}>
              {KIND_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
            </select>
          </div>
          <div className="field" style={{ margin: 0 }}>
            <label className="label">From</label>
            <input className="input" type="date" value={from} onChange={e => setFrom(e.target.value)} max={to || undefined} style={{ width: 170 }}/>
          </div>
          <div className="field" style={{ margin: 0 }}>
            <label className="label">To</label>
            <input className="input" type="date" value={to} onChange={e => setTo(e.target.value)} min={from || undefined} style={{ width: 170 }}/>
          </div>
          {hasFilters && (
            <button className="btn ghost" onClick={clearFilters}>
              <NIcon name="x" size={14}/>Clear filters
            </button>
          )}
        </div>

        {/* List */}
        <div className="cx-card flush" style={{ marginTop: 20 }}>
          {err && <div className="ui-alert red" style={{ margin: 16 }}>{err}</div>}
          {!err && items.length === 0 && (
            <window.AppUI.EmptyState icon="bell"
              title={loading ? "Loading…" : hasFilters ? "No matches" : "No notifications yet"}
              hint={loading ? null : hasFilters ? "No notifications match these filters." : "New activity will show up here."}/>
          )}

          <div className="ui-list">
            {items.map(n => {
              const m = meta(n);
              const p = n.payload || {};
              const photo = n.kind === "progress_extra_logged" && p.photo_path
                ? `${window.AppApi.base}/progress-photos/${p.photo_path}` : null;
              return (
                <div key={n.id} onClick={() => { if (!n.read_at) markRead(n.id); }}
                  className={`ui-row${n.read_at ? "" : " clickable"}`}
                  style={{
                    padding: "14px 20px", alignItems: "flex-start",
                    background: n.read_at ? "transparent" : "color-mix(in srgb, var(--accent) 5%, transparent)",
                  }}>
                  <span style={{ width: 8, flexShrink: 0, paddingTop: 7 }}>
                    {!n.read_at && <span className="ui-notif-dot" style={{ display: "block", width: 7, height: 7 }}/>}
                  </span>
                  <div className="ui-row-main">
                    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4, flexWrap: "wrap" }}>
                      <span className={`pill ${m.pill}`}>{m.label}</span>
                      <span className="muted tabular" style={{ fontSize: 12, marginLeft: "auto" }} title={fmtAbs(n.created_at)}>
                        {fmtAbs(n.created_at)} · {relTime(n.created_at)}
                      </span>
                    </div>
                    <div className="ui-row-title" style={{ fontWeight: n.read_at ? 500 : 600 }}>{m.title}</div>
                    {m.sub && <div className="ui-row-sub" style={{ 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: "var(--radius-ctl)", border: "1px solid var(--line)" }}/>
                    </a>
                  )}
                </div>
              );
            })}
          </div>

          {hasMore && (
            <div style={{ padding: 14, textAlign: "center", borderTop: "1px solid var(--line-soft)" }}>
              <button className="btn sm" onClick={() => fetchPage(offset, false)} disabled={loading}>
                {loading ? "Loading…" : "Load more"}
              </button>
            </div>
          )}
        </div>
      </div>
    );
  }

  window.NotificationsScreen = NotificationsScreen;
})();
