// ============================================================================
// IMS — OS / CM Inbox
// Tabs: All | Bundles | Notifications
// Bundle cards: rich agreement detail, Quick Accept, Review flow
// Notification cards: status overrides, payment processed, admin messages
// ============================================================================

// Static sample notifications per role — these represent non-bundle inbox items
const SAMPLE_NOTIFICATIONS = {
  outreach: [
    {
      id: "NOTIF-OS-01",
      kind: "override",
      read: false,
      at: "Today · 09:55",
      title: "Admin changed a status",
      body: "Farah K. changed Mubarak Hassan's status to Contacted. Open their profile to confirm receipt.",
      action: "in-progress",
      actionLabel: "Go to In Progress",
    },
    {
      id: "NOTIF-OS-02",
      kind: "payment",
      read: true,
      at: "Apr 17 · 14:00",
      title: "Payment cycle processed",
      body: "OS-1042 (Apr 11 – Apr 17) has been marked Paid. $8.40 has been processed to your account.",
      action: "payments",
      actionLabel: "View Payments",
    },
    {
      id: "NOTIF-OS-03",
      kind: "info",
      read: true,
      at: "Apr 14 · 11:20",
      title: "Reminder: conversation upload",
      body: "3 influencers are waiting for their conversation to be submitted. Complete by end of day.",
      action: "announcements",
      actionLabel: "Upload Now",
    },
  ],
  collab: [
    {
      id: "NOTIF-CM-01",
      kind: "override",
      read: false,
      at: "Today · 10:05",
      title: "Admin changed a stage",
      body: "Farah K. updated Noura Khaled's stage to Stage 2 · In Progress. Open their profile to confirm receipt.",
      action: "in-progress",
      actionLabel: "Go to In Progress",
    },
    {
      id: "NOTIF-CM-02",
      kind: "payment",
      read: false,
      at: "Apr 17 · 14:00",
      title: "Stage payment processed",
      body: "CM-0091 (Apr 11 – Apr 17): Stage completions totalling $95.00 have been marked Paid.",
      action: "payments",
      actionLabel: "View Payments",
    },
    {
      id: "NOTIF-CM-03",
      kind: "info",
      read: true,
      at: "Apr 12 · 09:00",
      title: "Commission due — 7-day window",
      body: "Aisha Okafor's content has been live for 7 days. Finance has been informed to calculate your commission.",
      action: "in-progress",
      actionLabel: "View Influencer",
    },
  ],
};

const NOTIF_META = {
  override:           { tone: "warn", label: "Status Override",    icon: "warn"  },
  payment:            { tone: "ok",   label: "Payment",            icon: "check" },
  "request-response": { tone: "info", label: "Admin Response",     icon: "info"  },
  "request-resolved": { tone: "ok",   label: "Request Resolved",   icon: "check" },
  "stage-complete":   { tone: "ok",   label: "Stage Completed",    icon: "check" },
  info:               { tone: "info", label: "Info",               icon: "info"  },
  "returning-assigned": { tone: "accent", label: "Returning Assigned", icon: "info" },
};

function RoleInboxPage() {
  const { role, data, activePersonId, notify, setPage, acceptBundle, markBundleRead, markNotifRead, dismissNotif } = useApp();
  const allBundles = role === "outreach" ? data.osInbox : data.cmInbox;
  const bundles = activePersonId
    ? allBundles.filter(b => b.specialistId === activePersonId || b.cmId === activePersonId)
    : allBundles;
  const notifs = role === "outreach" ? (data.osNotifications || []) : (data.cmNotifications || []);

  const [open, setOpen] = useState(null);
  const [tab,  setTab]  = useState("all");
  const [bundlePg,  setBundlePg]  = useState(1);
  const [notifPg,   setNotifPg]   = useState(1);
  const [bundleSearch, setBundleSearch] = useState("");
  const [notifSearch,  setNotifSearch]  = useState("");
  const [notifReadFilter,  setNotifReadFilter]  = useState("all"); // "all" | "unread" | "read"
  const [bundleReadFilter, setBundleReadFilter] = useState("all"); // "all" | "unread" | "read"

  const BUNDLES_PER_PAGE  = 8;
  const NOTIFS_PER_PAGE   = 10;
  const ALL_TAB_BUNDLE_CAP = 3;   // "All" tab preview cap

  const handleMarkBundleRead = (id) => markBundleRead(role, id);
  const handleMarkNotifRead  = (id) => markNotifRead(role, id);
  const handleDismissNotif   = (id) => dismissNotif(role, id);

  const { unreadBundles, unreadNotifs } = useMemo(() => ({
    unreadBundles: bundles.filter(b => !b.read).length,
    unreadNotifs:  notifs.filter(n => !n.read).length,
  }), [bundles, notifs]);
  const totalUnread = unreadBundles + unreadNotifs;

  const showBundles = tab === "all" || tab === "bundles";
  const showNotifs  = tab === "all" || tab === "notifications";

  // Pre-compute per-bundle previouslyRejected summary once — avoids triple filter inside card map
  const bundleMeta = useMemo(() => {
    const m = {};
    bundles.forEach(b => {
      const rejInfs = (b.influencers || []).filter(inf => inf.previouslyRejected);
      m[b.id] = { rejCount: rejInfs.length, hasRej: rejInfs.length > 0 };
    });
    return m;
  }, [bundles]);

  // Filtered + paginated bundles
  const filteredBundles = useMemo(() => {
    let list = bundles;
    if (bundleReadFilter === "unread") list = list.filter(b => !b.read);
    else if (bundleReadFilter === "read") list = list.filter(b => b.read);
    if (!bundleSearch) return list;
    const q = bundleSearch.toLowerCase();
    return list.filter(b =>
      b.id.toLowerCase().includes(q) ||
      (b.campaignName || "").toLowerCase().includes(q) ||
      (b.assignedBy || "").toLowerCase().includes(q)
    );
  }, [bundles, bundleSearch, bundleReadFilter]);

  const bundleTotalPages = Math.max(1, Math.ceil(filteredBundles.length / BUNDLES_PER_PAGE));
  const bundlesForTab = tab === "bundles"
    ? filteredBundles.slice((bundlePg - 1) * BUNDLES_PER_PAGE, bundlePg * BUNDLES_PER_PAGE)
    : bundles.slice(0, ALL_TAB_BUNDLE_CAP);
  const bundleOverflow = tab === "all" && bundles.length > ALL_TAB_BUNDLE_CAP;

  // Filtered + paginated notifications
  const filteredNotifs = useMemo(() => {
    let list = notifs;
    if (notifReadFilter === "unread") list = list.filter(n => !n.read);
    else if (notifReadFilter === "read") list = list.filter(n => n.read);
    if (!notifSearch) return list;
    const q = notifSearch.toLowerCase();
    return list.filter(n =>
      (n.title || "").toLowerCase().includes(q) ||
      (n.body  || "").toLowerCase().includes(q)
    );
  }, [notifs, notifSearch, notifReadFilter]);

  const notifTotalPages = Math.max(1, Math.ceil(filteredNotifs.length / NOTIFS_PER_PAGE));
  const notifsForTab = tab === "notifications"
    ? filteredNotifs.slice((notifPg - 1) * NOTIFS_PER_PAGE, notifPg * NOTIFS_PER_PAGE)
    : notifs.slice(0, 5);
  const notifOverflow = tab === "all" && notifs.length > 5;

  const switchTab = (t) => { setTab(t); setBundlePg(1); setNotifPg(1); setBundleSearch(""); setNotifSearch(""); setNotifReadFilter("all"); setBundleReadFilter("all"); };

  const hasBundles = bundles.length > 0;
  const hasNotifs  = notifs.length > 0;
  const isEmpty    = !hasBundles && !hasNotifs;

  if (open) return (
    <BundleReview
      bundle={open}
      onClose={() => setOpen(null)}
      onDone={(msg, accepted, rejected) => {
        acceptBundle(open.id, accepted, rejected, role === "outreach" ? "outreach" : "leads");
        setOpen(null);
        notify(msg);
        setPage({ key: "in-progress" });
      }}
    />
  );

  return (
    <div className="page">
      {/* ── Page header ── */}
      <div className="page-head">
        <div>
          <h1>Inbox</h1>
          <div className="subtitle">
            Bundle assignments and notifications from Admin.
          </div>
        </div>
        <div className="meta">
          {totalUnread > 0 && <Chip tone="alert" xs>{totalUnread} unread</Chip>}
          <span>{bundles.length + notifs.length} total</span>
        </div>
      </div>

      {/* ── Filter tabs ── */}
      <div className="tabs" style={{ marginBottom: 0, position: "relative", top: "auto", background: "transparent" }}>
        <div className={`tab ${tab === "all" ? "active" : ""}`} onClick={() => switchTab("all")}>
          All
          {totalUnread > 0 && <span className="count" style={{ background: "var(--accent)", color: "#fff" }}>{totalUnread}</span>}
        </div>
        <div className={`tab ${tab === "bundles" ? "active" : ""}`} onClick={() => switchTab("bundles")}>
          Bundles
          <span className="count">{bundles.length}</span>
          {unreadBundles > 0 && <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--accent)", display: "inline-block", marginLeft: 2 }} />}
        </div>
        <div className={`tab ${tab === "notifications" ? "active" : ""}`} onClick={() => switchTab("notifications")}>
          Notifications
          <span className="count">{notifs.length}</span>
          {unreadNotifs > 0 && <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--accent)", display: "inline-block", marginLeft: 2 }} />}
        </div>
      </div>

      <div style={{ marginTop: 16, display: "flex", flexDirection: "column", gap: 20 }}>

        {/* ══ BUNDLES SECTION ══ */}
        {showBundles && hasBundles && (
          <div>
            {/* Section header */}
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10 }}>
              <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", flex: 1, display: "flex", alignItems: "center", gap: 8 }}>
                Bundle Assignments
                <span style={{ background: "var(--accent)", color: "#fff", borderRadius: 4, padding: "1px 6px", fontSize: 10, fontFamily: "var(--font-mono)" }}>{bundles.length}</span>
              </div>
              {tab === "bundles" && (
                <div style={{ display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap" }}>
                  {[
                    { key: "all",    label: "All",    count: bundles.length },
                    { key: "unread", label: "Unread", count: bundles.filter(b => !b.read).length },
                    { key: "read",   label: "Read",   count: bundles.filter(b =>  b.read).length },
                  ].map(f => (
                    <button
                      key={f.key}
                      className={`btn sm ${bundleReadFilter === f.key ? "primary" : "ghost"}`}
                      style={{ fontSize: 11, padding: "2px 8px" }}
                      onClick={() => { setBundleReadFilter(f.key); setBundlePg(1); }}
                    >
                      {f.label}
                      <span style={{
                        background: bundleReadFilter === f.key ? "rgba(255,255,255,0.25)" : "var(--line-2)",
                        color: bundleReadFilter === f.key ? "#fff" : "var(--ink-3)",
                        borderRadius: 4, padding: "0 5px", fontSize: 10, fontFamily: "var(--font-mono)", marginLeft: 4,
                      }}>{f.count}</span>
                    </button>
                  ))}
                  <div className="search" style={{ maxWidth: 200 }}>
                    <Ic.search />
                    <input placeholder="Search bundles…" value={bundleSearch} onChange={e => { setBundleSearch(e.target.value); setBundlePg(1); }} />
                    {bundleSearch && <button className="search-clear" onClick={() => { setBundleSearch(""); setBundlePg(1); }}><Ic.x /></button>}
                  </div>
                </div>
              )}
            </div>

            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              {bundlesForTab.map(b => {
                const isRead = b.read;
                const isLead = b.id.startsWith("LB") && !b.isReturning;
                // Parse CM stage amounts from agreement string for structured display
                const stageAmounts = isLead
                  ? ((b.agreement || "").match(/Stage \d \$\d+/g) || [])
                  : null;
                const commissionPart = isLead
                  ? (b.agreement || "").match(/(\d+%) commission · (\d+ months)/)
                  : null;

                return (
                  <div
                    key={b.id}
                    className="card"
                    style={{
                      borderLeft: isRead ? "3px solid transparent" : "3px solid var(--accent)",
                      transition: "border-left-color 0.2s",
                    }}
                    onClick={() => handleMarkBundleRead(b.id)}
                  >
                    {/* ── Card top row ── */}
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16 }}>

                      {/* Left: info */}
                      <div style={{ flex: 1, minWidth: 0 }}>
                        {/* ID + badges */}
                        <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap", marginBottom: 10 }}>
                          <BundleIdChip id={b.id} />
                          {!isRead && (
                            <Chip tone="accent-soft" xs>New</Chip>
                          )}
                          <Chip tone={isLead ? "accent" : "info"} xs>
                            {isLead ? "Lead Bundle" : "Outreach Bundle"}
                          </Chip>
                          {b.campaignName && (
                            <Chip tone="info" xs>{b.campaignName}</Chip>
                          )}
                          {b.isReturning && (
                            <Chip tone="accent" xs>Returning — Stage 2-4 only</Chip>
                          )}
                          <span className="text-mono text-xs text-mute">{b.assignedAt}</span>
                        </div>
                        {b.isReturning && (
                          <div className="banner info" style={{ marginBottom: 8 }}>
                            <Ic.info />
                            <div>These influencers have an existing contract. Stage 1 will be pre-completed. You start from Stage 2.</div>
                          </div>
                        )}

                        {/* Headline */}
                        <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 6, color: "var(--ink)" }}>
                          {b.count} {isLead ? "potential leads" : "influencers"} assigned by {b.assignedBy}
                        </div>

                        {/* Agreement detail — structured for CM, single line for OS */}
                        {isLead && stageAmounts ? (
                          <div style={{ marginTop: 8 }}>
                            <div className="text-mono text-xs text-mute" style={{
                              textTransform: "uppercase", letterSpacing: "0.1em", marginBottom: 6,
                            }}>
                              Your earnings for this bundle
                            </div>
                            <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                              {stageAmounts.map((s, i) => (
                                <span key={i} style={{
                                  display: "inline-flex", alignItems: "center",
                                  border: "1px solid var(--line-2)", borderRadius: 4,
                                  padding: "3px 8px", fontSize: 11,
                                  fontFamily: "var(--font-mono)", fontWeight: 600,
                                  background: "var(--bg-2)", color: "var(--ink-2)",
                                }}>{s}</span>
                              ))}
                              {commissionPart && (
                                <span style={{
                                  display: "inline-flex", alignItems: "center",
                                  border: "1px solid var(--line-2)", borderRadius: 4,
                                  padding: "3px 8px", fontSize: 11,
                                  fontFamily: "var(--font-mono)", fontWeight: 600,
                                  background: "var(--bg-2)", color: "var(--ink-2)",
                                }}>
                                  {commissionPart[1]} commission · {commissionPart[2]}
                                </span>
                              )}
                            </div>
                          </div>
                        ) : (
                          <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 6 }}>
                            {(b.agreement || "").split(" · ").filter(Boolean).map((part, i) => (
                              <span key={i} style={{
                                display: "inline-flex", alignItems: "center",
                                border: "1px solid var(--line-2)", borderRadius: 4,
                                padding: "3px 8px", fontSize: 11,
                                fontFamily: "var(--font-mono)", fontWeight: 600,
                                background: "var(--bg-2)", color: "var(--ink-2)",
                              }}>{part}</span>
                            ))}
                          </div>
                        )}

                        {/* Previously rejected warning — counts from pre-computed bundleMeta */}
                        {bundleMeta[b.id]?.hasRej && (
                          <div style={{
                            display: "inline-flex", alignItems: "center", gap: 6,
                            marginTop: 10, padding: "5px 10px",
                            background: "var(--warn-bg)", border: "1px solid var(--warn)",
                            borderRadius: 4, fontSize: 12, color: "var(--warn-dark)",
                          }}>
                            <Ic.warn />
                            {bundleMeta[b.id].rejCount} influencer{bundleMeta[b.id].rejCount > 1 ? "s" : ""} in this bundle
                            {bundleMeta[b.id].rejCount > 1 ? " were" : " was"} previously rejected — review before accepting.
                          </div>
                        )}
                      </div>

                      {/* Right: actions */}
                      <div style={{ display: "flex", flexDirection: "column", gap: 8, flexShrink: 0 }}>
                        <button
                          className="btn primary"
                          style={{ whiteSpace: "nowrap" }}
                          onClick={(e) => {
                            e.stopPropagation();
                            acceptBundle(b.id, b.influencers, [], b.cmId ? (isLead ? "leads" : "collab") : "outreach");
                            handleMarkBundleRead(b.id);
                            notify(`${b.count} ${isLead ? "leads" : "influencers"} transferred to your In Progress list.`);
                            setPage({ key: "in-progress" });
                          }}
                        >
                          Quick Accept <Ic.check />
                        </button>
                        <button
                          className="btn"
                          style={{ whiteSpace: "nowrap" }}
                          onClick={(e) => { e.stopPropagation(); handleMarkBundleRead(b.id); setOpen(b); }}
                        >
                          Review Bundle <Ic.arrowRight />
                        </button>
                      </div>
                    </div>

                    {/* ── Influencer avatar strip ── */}
                    {b.influencers?.length > 0 && (
                      <div style={{
                        marginTop: 14, paddingTop: 12,
                        borderTop: "1px solid var(--line)",
                        display: "flex", alignItems: "center", gap: 6,
                      }}>
                        <span className="text-mono text-xs text-mute" style={{ marginRight: 4, whiteSpace: "nowrap" }}>
                          In this bundle:
                        </span>
                        <div style={{ display: "flex", gap: 0 }}>
                          {b.influencers.slice(0, 6).map((inf, idx) => {
                            const initials = inf.name.split(" ").map(n => n[0]).slice(0, 2).join("");
                            return (
                              <div
                                key={inf.id}
                                title={inf.name}
                                style={{
                                  width: 26, height: 26, borderRadius: "50%",
                                  background: inf.previouslyRejected ? "var(--bad)" : "var(--bg-3)",
                                  color: inf.previouslyRejected ? "#fff" : "var(--ink-2)",
                                  border: "2px solid var(--bg)",
                                  display: "flex", alignItems: "center", justifyContent: "center",
                                  fontSize: 9, fontWeight: 700, fontFamily: "var(--font-mono)",
                                  marginLeft: idx === 0 ? 0 : -8,
                                  position: "relative", zIndex: b.influencers.length - idx,
                                  cursor: "default",
                                }}
                              >
                                {initials}
                              </div>
                            );
                          })}
                          {b.influencers.length > 6 && (
                            <div style={{
                              width: 26, height: 26, borderRadius: "50%",
                              background: "var(--line-2)", color: "var(--ink-3)",
                              border: "2px solid var(--bg)",
                              display: "flex", alignItems: "center", justifyContent: "center",
                              fontSize: 9, fontWeight: 700, fontFamily: "var(--font-mono)",
                              marginLeft: -8,
                            }}>
                              +{b.influencers.length - 6}
                            </div>
                          )}
                        </div>
                        {bundleMeta[b.id]?.hasRej && (
                          <span style={{ fontSize: 11, color: "var(--bad)", fontFamily: "var(--font-mono)", marginLeft: 4 }}>
                            red = previously rejected
                          </span>
                        )}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>

            {/* "All" tab overflow CTA */}
            {bundleOverflow && (
              <button
                className="btn ghost sm"
                style={{ marginTop: 10, width: "100%", justifyContent: "center" }}
                onClick={() => switchTab("bundles")}
              >
                View all {bundles.length} bundles <Ic.arrowRight />
              </button>
            )}

            {/* Bundles tab pagination */}
            {tab === "bundles" && bundleTotalPages > 1 && (
              <div style={{ marginTop: 12 }}>
                <TablePagination page={bundlePg} totalPages={bundleTotalPages} onPage={setBundlePg} total={filteredBundles.length} perPage={BUNDLES_PER_PAGE} />
              </div>
            )}
            {tab === "bundles" && filteredBundles.length === 0 && bundleSearch && (
              <div style={{ textAlign: "center", padding: 24, color: "var(--ink-3)", fontSize: 13 }}>No bundles match "{bundleSearch}".</div>
            )}
          </div>
        )}

        {/* Bundles empty state (only when Bundles tab is active) */}
        {!hasBundles && tab === "bundles" && (
          <div className="card" style={{ textAlign: "center", padding: "40px 24px", color: "var(--ink-3)" }}>
            <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 4 }}>No pending bundles</div>
            <div className="text-small">You'll be notified via IMS Inbox when Admin assigns a new bundle.</div>
          </div>
        )}

        {/* ══ NOTIFICATIONS SECTION ══ */}
        {showNotifs && hasNotifs && (
          <div>
            {/* Section header */}
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 10, flexWrap: "wrap" }}>
              <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", flex: 1, display: "flex", alignItems: "center", gap: 8 }}>
                Notifications
                {unreadNotifs > 0 && <span style={{ background: "var(--accent)", color: "#fff", borderRadius: 4, padding: "1px 6px", fontSize: 10, fontFamily: "var(--font-mono)" }}>{unreadNotifs} unread</span>}
              </div>
              {/* Filter pills + actions — only on Notifications tab */}
              {tab === "notifications" && (
                <>
                  <div style={{ display: "flex", gap: 4 }}>
                    {[
                      { key: "all",    label: "All",    count: notifs.length },
                      { key: "unread", label: "Unread", count: unreadNotifs },
                      { key: "read",   label: "Read",   count: notifs.length - unreadNotifs },
                    ].map(f => (
                      <button
                        key={f.key}
                        className={`btn sm ${notifReadFilter === f.key ? "primary" : "ghost"}`}
                        style={{ fontSize: 11, padding: "2px 10px", display: "flex", alignItems: "center", gap: 5 }}
                        onClick={() => { setNotifReadFilter(f.key); setNotifPg(1); }}
                      >
                        {f.label}
                        <span style={{
                          background: notifReadFilter === f.key ? "rgba(255,255,255,0.25)" : "var(--line-2)",
                          color: notifReadFilter === f.key ? "#fff" : "var(--ink-3)",
                          borderRadius: 4, padding: "0 5px", fontSize: 10, fontFamily: "var(--font-mono)",
                        }}>{f.count}</span>
                      </button>
                    ))}
                  </div>
                  {notifsForTab.some(n => !n.read) && (
                    <button
                      className="btn ghost sm"
                      style={{ fontSize: 11, whiteSpace: "nowrap" }}
                      onClick={() => notifsForTab.filter(n => !n.read).forEach(n => handleMarkNotifRead(n.id))}
                    >
                      Mark page as read
                    </button>
                  )}
                  <div className="search" style={{ maxWidth: 220 }}>
                    <Ic.search />
                    <input placeholder="Search notifications…" value={notifSearch} onChange={e => { setNotifSearch(e.target.value); setNotifPg(1); }} />
                    {notifSearch && <button className="search-clear" onClick={() => { setNotifSearch(""); setNotifPg(1); }}><Ic.x /></button>}
                  </div>
                </>
              )}
            </div>

            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {notifsForTab.map(n => {
                const meta = NOTIF_META[n.kind] || NOTIF_META.info;
                return (
                  <div
                    key={n.id}
                    className="card"
                    style={{
                      borderLeft: n.read ? "3px solid transparent" : "3px solid var(--accent)",
                      cursor: "pointer",
                      transition: "border-left-color 0.2s",
                    }}
                    onClick={() => handleMarkNotifRead(n.id)}
                  >
                    <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 16 }}>
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ display: "flex", gap: 6, alignItems: "center", flexWrap: "wrap", marginBottom: 8 }}>
                          {!n.read && (
                            <span style={{ width: 6, height: 6, borderRadius: 99, background: "var(--accent)", flexShrink: 0 }} />
                          )}
                          <Chip tone={meta.tone} xs>{meta.label}</Chip>
                          <span className="text-mono text-xs text-mute">{n.at}</span>
                        </div>
                        <div style={{ fontWeight: 600, fontSize: 13.5, marginBottom: 4, color: "var(--ink)" }}>
                          {n.title}
                        </div>
                        <div style={{ fontSize: 13, color: "var(--ink-2)", lineHeight: 1.55 }}>
                          {n.body}
                        </div>
                      </div>
                      <div style={{ display: "flex", flexDirection: "column", gap: 6, flexShrink: 0, alignItems: "flex-end" }}>
                        {n.action && n.action !== "inbox" && (
                          <button className="btn sm" onClick={(e) => { e.stopPropagation(); handleMarkNotifRead(n.id); setPage({ key: n.action }); }}>
                            {n.actionLabel} <Ic.arrowRight />
                          </button>
                        )}
                        <button className="btn ghost sm" onClick={(e) => { e.stopPropagation(); handleDismissNotif(n.id); }}>
                          Dismiss
                        </button>
                      </div>
                    </div>
                  </div>
                );
              })}
              {notifsForTab.length === 0 && (
                <div style={{ textAlign: "center", padding: "32px 0", color: "var(--ink-3)", fontSize: 13 }}>
                  No notifications{notifSearch ? ` match "${notifSearch}"` : ""}.
                </div>
              )}
            </div>

            {/* "All" tab overflow CTA */}
            {notifOverflow && (
              <button
                className="btn ghost sm"
                style={{ marginTop: 10, width: "100%", justifyContent: "center" }}
                onClick={() => switchTab("notifications")}
              >
                View all {notifs.length} notifications <Ic.arrowRight />
              </button>
            )}

            {/* Notifications tab pagination */}
            {tab === "notifications" && notifTotalPages > 1 && (
              <div style={{ marginTop: 12 }}>
                <TablePagination page={notifPg} totalPages={notifTotalPages} onPage={setNotifPg} total={filteredNotifs.length} perPage={NOTIFS_PER_PAGE} />
              </div>
            )}
            {tab === "notifications" && filteredNotifs.length === 0 && notifSearch && (
              <div style={{ textAlign: "center", padding: 24, color: "var(--ink-3)", fontSize: 13 }}>No notifications match "{notifSearch}".</div>
            )}
          </div>
        )}

        {/* Notifications empty state (only when Notifications tab is active) */}
        {!hasNotifs && tab === "notifications" && (
          <div className="card" style={{ textAlign: "center", padding: "40px 24px", color: "var(--ink-3)" }}>
            <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 4 }}>No notifications</div>
            <div className="text-small">Payment confirmations, status overrides, and admin messages appear here.</div>
          </div>
        )}

        {/* Full empty state (All tab, nothing at all) */}
        {isEmpty && tab === "all" && (
          <div className="card" style={{ textAlign: "center", padding: "48px 24px", color: "var(--ink-3)" }}>
            <div style={{ fontSize: 13, fontWeight: 500, marginBottom: 4 }}>Inbox empty — all caught up.</div>
            <div className="text-small">New bundles and notifications will appear here.</div>
          </div>
        )}
      </div>
    </div>
  );
}

function BundleReview({ bundle, onClose, onDone }) {
  const [list, setList] = useState(bundle.influencers.map(i => ({ ...i, rejected: false })));
  const [rejectFor, setRejectFor] = useState(null);
  const [reason, setReason] = useState("");
  const [pg, setPg]         = useState(1);
  const [rejPg, setRejPg]   = useState(1);
  const perPage = 8;
  const rejPerPage = 8;

  const toggle = (id) => {
    setList(list.map(i => i.id === id ? { ...i, rejected: !i.rejected, rejectReason: i.rejected ? null : i.rejectReason } : i));
  };

  const rejectAll = () => { setList(list.map(i => ({ ...i, rejected: true }))); setPg(1); setRejPg(1); };
  const keep     = list.filter(i => !i.rejected);
  const rejected = list.filter(i => i.rejected);

  const totalPages    = Math.max(1, Math.ceil(keep.length     / perPage));
  const rejTotalPages = Math.max(1, Math.ceil(rejected.length / rejPerPage));
  const pagedKeep     = keep.slice((pg    - 1) * perPage,    pg    * perPage);
  const pagedRejected = rejected.slice((rejPg - 1) * rejPerPage, rejPg * rejPerPage);

  const doReject = () => {
    setList(list.map(i => i.id === rejectFor.id ? { ...i, rejected: true, rejectReason: reason } : i));
    setRejectFor(null); setReason("");
  };

  return (
    <div className="page">
      <button className="btn ghost sm" onClick={onClose}><Ic.arrowLeft /> Back to inbox</button>
      <div className="page-head" style={{ marginTop: 12 }}>
        <div>
          <h1>Review Bundle {bundle.id}</h1>
          <div className="subtitle">Reject any influencers you can't work with. Rejections go to the Admin Inbox.</div>
        </div>
        <div style={{ display: "flex", gap: 8 }}>
          {keep.length > 0 && (
            <button className="btn" onClick={rejectAll}>Reject All</button>
          )}
          {/* Fix 6: when all rejected, show "Confirm Full Rejection" instead of "Accept Remaining · 0" */}
          {keep.length === 0 ? (
            <button
              className="btn"
              style={{ background: "var(--alert)", color: "#fff", borderColor: "var(--alert)" }}
              onClick={() => onDone(
                `All ${rejected.length} influencers rejected and sent to Admin Inbox.`,
                [],
                rejected.map(i => ({ ...i, _rejectReason: i.rejectReason }))
              )}
            >
              Confirm Full Rejection · {rejected.length}
            </button>
          ) : (
            <button className="btn primary" onClick={() => onDone(
              rejected.length
                ? `${rejected.length} rejected. Remaining ${keep.length} moved to your In Progress.`
                : `${keep.length} influencers transferred to your In Progress list.`,
              keep,
              rejected.map(i => ({ ...i, _rejectReason: i.rejectReason }))
            )}>
              {rejected.length > 0 ? "Accept Remaining" : "Accept"} · {keep.length} <Ic.arrowRight />
            </button>
          )}
        </div>
      </div>

      <div className="table-wrap">
        <table className="ims">
          <thead><tr><th>Influencer</th><th>Platform</th><th>Category</th><th>Location</th><th className="num">Followers</th><th></th></tr></thead>
          <tbody>
            {pagedKeep.length === 0 && (
              <tr><td colSpan={6} style={{ textAlign: "center", padding: "32px 0", color: "var(--ink-3)", fontFamily: "var(--font-mono)", fontSize: 12, letterSpacing: "0.06em" }}>
                ALL REJECTED — click "Accept Remaining" to confirm or undo individual rejections below.
              </td></tr>
            )}
            {pagedKeep.map(i => (
              <tr key={i.id}>
                <td>
                  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                    <InfCell name={i.name} handle={i.handle} />
                    {i.previouslyRejected && (
                      <span className="pill" style={{ color: "var(--bad)", background: "var(--bad-bg)", borderColor: "transparent" }}>
                        <Ic.info /> Previously Rejected
                      </span>
                    )}
                  </div>
                </td>
                <td>{i.platform}</td>
                <td>{i.category}</td>
                <td className="mono">{i.location}</td>
                <td className="num">{i.followers}</td>
                <td style={{ display: "flex", gap: 6, justifyContent: "flex-end", alignItems: "center" }}>
                  <span style={{
                    display: "inline-flex", alignItems: "center", gap: 4,
                    fontSize: 11, fontFamily: "var(--font-mono)", color: "var(--ok)",
                    background: "var(--ok-bg)", borderRadius: 4, padding: "3px 8px",
                    border: "1px solid color-mix(in srgb, var(--ok) 30%, transparent)",
                  }}>
                    <Ic.check /> Will Accept
                  </span>
                  <button className="btn sm danger" onClick={() => setRejectFor(i)}>Reject</button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      <TablePagination page={pg} totalPages={totalPages} onPage={setPg} total={keep.length} perPage={perPage} />

      {rejected.length > 0 && (
        <>
          <div className="text-mono text-xs text-mute" style={{ textTransform: "uppercase", letterSpacing: "0.12em", margin: "22px 0 10px", display: "flex", alignItems: "center", gap: 10 }}>
            <span>Rejected · {rejected.length} — will go to Admin Inbox</span>
          </div>
          <div className="table-wrap" style={{ background: "var(--bad-bg)" }}>
            <table className="ims">
              <tbody>
                {pagedRejected.map(i => (
                  <tr key={i.id}>
                    <td><InfCell name={i.name} handle={i.handle} /></td>
                    <td className="text-small text-mute">{i.rejectReason || "—"}</td>
                    <td style={{ textAlign: "right" }}>
                      <button className="btn sm" onClick={() => toggle(i.id)}>Undo</button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          {rejTotalPages > 1 && (
            <TablePagination page={rejPg} totalPages={rejTotalPages} onPage={setRejPg} total={rejected.length} perPage={rejPerPage} />
          )}
        </>
      )}

      {rejectFor && (
        <Modal open={true} onClose={() => setRejectFor(null)} title={`Reject ${rejectFor.name}?`} sub="Will be sent to Admin Inbox"
          foot={<><button className="btn" onClick={() => setRejectFor(null)}>Cancel</button><button className="btn danger" onClick={doReject} disabled={!reason.trim()}>Reject</button></>}>
          <textarea className="textarea" rows="3" value={reason} onChange={e => setReason(e.target.value)} placeholder="Reason for rejection (required)…" autoFocus />
          {!reason.trim() && <div style={{ fontSize: 11, color: "var(--ink-3)", marginTop: 4 }}>A reason is required before rejecting.</div>}
        </Modal>
      )}
    </div>
  );
}

// ============================================================================
// Announcements page — conversation-upload tasks for OS
// ============================================================================

function ScreenshotUploadModal({ influencer, onClose, onDone }) {
  const [uploaded, setUploaded] = useState(false);
  const [aiResult, setAiResult] = useState(null);

  const doUpload = () => {
    setUploaded(true);
    setTimeout(() => {
      setAiResult(Math.random() < 0.15 ? "warn" : "ok");
    }, 700);
  };

  return (
    <Modal open={true} onClose={onClose}
      title={`Upload Screenshot · ${influencer.name}`}
      sub="Evidence of contact"
      foot={<>
        <span className="text-xs text-mute">AI vision model will verify the screenshot.</span>
        <div style={{ display: "flex", gap: 8 }}>
          <button className="btn" onClick={onClose}>Cancel</button>
          <button className="btn primary" disabled={!uploaded || aiResult == null}
            onClick={() => onDone(influencer.id, aiResult)}>
            {aiResult === "warn" ? "Continue anyway" : "Save Screenshot"}
          </button>
        </div>
      </>}>
      <div className="text-mute" style={{ marginBottom: 14 }}>Upload a screenshot of your DM or email contact with {influencer.name}.</div>
      {!uploaded && (
        <div onClick={doUpload} style={{ cursor: "pointer" }}>
          <div className="shot-placeholder" style={{ height: 180 }}>
            <div style={{ textAlign: "center" }}><Ic.upload /><div style={{ marginTop: 8 }}>Click to upload screenshot</div></div>
          </div>
        </div>
      )}
      {uploaded && (
        <>
          <div className="shot-placeholder" style={{ height: 180 }}>screenshot · contact.png</div>
          {aiResult === null && <div className="banner info" style={{ marginTop: 12 }}><Ic.info /><div>AI vision model checking…</div></div>}
          {aiResult === "ok" && (
            <div className="banner info" style={{ marginTop: 12, background: "var(--ok-bg)", borderLeftColor: "var(--ok)" }}>
              <span className="tick" /><div><strong>AI verified</strong> — this appears to be a valid DM screenshot.</div>
            </div>
          )}
          {aiResult === "warn" && (
            <div className="banner" style={{ marginTop: 12 }}>
              <Ic.warn /><div><strong>Issue detected.</strong> What you uploaded doesn't seem to be a screenshot of a message. Admin will see a flag.</div>
            </div>
          )}
        </>
      )}
    </Modal>
  );
}

function AnnouncementsPage() {
  const { data, activePersonId, notify, updateInfluencer, setPage } = useApp();

  // Only show influencers who have NOT uploaded a contact screenshot yet
  const pending = data.outreachInProgress.filter(r =>
    (!activePersonId || r.specialistId === activePersonId) &&
    r.status !== "Not Contacted" &&
    !r.screenshotUploaded
  );
  const done = data.outreachInProgress.filter(r =>
    (!activePersonId || r.specialistId === activePersonId) &&
    r.status !== "Not Contacted" &&
    r.screenshotUploaded
  ).length;

  const [uploadFor, setUploadFor] = useState(null);
  const [pg, setPg] = useState(1);
  const perPage = 8;
  const totalPages = Math.max(1, Math.ceil(pending.length / perPage));
  const pagedPending = pending.slice((pg - 1) * perPage, pg * perPage);

  const handleDone = (id, aiResult) => {
    updateInfluencer(id, {
      screenshotUploaded: true,
      aiVerified: aiResult === "ok",
      aiFlag: aiResult === "warn",
    });
    setUploadFor(null);
    notify("Screenshot saved. Evidence recorded on influencer profile.");
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <h1>Announcements</h1>
          <div className="subtitle">Influencers you've contacted but haven't uploaded a screenshot for yet.</div>
        </div>
      </div>

      <div className={`announce ${pending.length === 0 ? "done" : ""}`} style={{ marginTop: 14 }}>
        <span className="dot">Task</span>
        <span>
          {pending.length > 0
            ? <><strong>{pending.length} {pending.length === 1 ? "task" : "tasks"} pending.</strong> Upload the contact screenshot for each influencer below.</>
            : <><strong>{done} {done === 1 ? "task" : "tasks"} complete.</strong> All screenshots uploaded — great work!</>}
        </span>
      </div>

      <div className="table-wrap" style={{ marginTop: 14 }}>
        <table className="ims">
          <thead><tr><th>Influencer</th><th>Bundle</th><th>Status</th><th>Contacted</th><th></th></tr></thead>
          <tbody>
            {pagedPending.map(r => (
              <tr key={r.id} className="clickable" onClick={() => setUploadFor(r)}>
                <td><InfCell name={r.name} handle={r.handle} /></td>
                <td><BundleIdChip id={r.bundleId} /></td>
                <td><StatusChip status={r.status} /></td>
                <td className="mono text-xs text-mute">{r.contactedAt || "—"}</td>
                <td style={{ textAlign: "right" }}>
                  <button className="btn sm" onClick={(e) => { e.stopPropagation(); setUploadFor(r); }}>
                    Upload Screenshot <Ic.arrowRight />
                  </button>
                </td>
              </tr>
            ))}
            {pending.length === 0 && (
              <tr><td colSpan="5" style={{ textAlign: "center", padding: 40, color: "var(--ink-3)" }}>All caught up — no pending screenshots.</td></tr>
            )}
          </tbody>
        </table>
      </div>

      <TablePagination page={pg} totalPages={totalPages} onPage={setPg} total={pending.length} perPage={perPage} />

      {uploadFor && (
        <ScreenshotUploadModal
          influencer={uploadFor}
          onClose={() => setUploadFor(null)}
          onDone={handleDone}
        />
      )}
    </div>
  );
}

Object.assign(window, { RoleInboxPage, BundleReview, AnnouncementsPage });
