// Notifications — every @mention addressed to you, in one place.
// Read them, open the brand, and archive the ones you have handled.

function NotificationsPage({ currentUser, onNavigate, onToast }) {
  // Canonical team name, so "Aaron Sailis" receives anything sent to @Aaron.
  const me = resolveTeamName(currentUser);
  const [items, setItems] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [tab, setTab] = usePersistentState('notifications.tab', 'inbox');  // inbox | archived
  const [busy, setBusy] = React.useState(false);

  const load = React.useCallback(async () => {
    if (!me) { setLoading(false); return; }
    setLoading(true);
    try {
      const rows = await window.IPSEM_API.getNotifications(me, { limit: 200, includeArchived: true });
      setItems(Array.isArray(rows) ? rows : []);
    } catch (e) {
      console.error('notifications load failed:', e);
      onToast && onToast('Could not load notifications');
    } finally {
      setLoading(false);
    }
  }, [me]);

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

  const inbox    = items.filter((n) => !n.archivedAt);
  const archived = items.filter((n) => n.archivedAt);
  const unread   = inbox.filter((n) => !n.readAt);
  const shown    = tab === 'archived' ? archived : inbox;

  // Optimistic local patch. No reload on success: the server applied exactly
  // the patch we just applied here, and re-fetching all 200 rows after every
  // click both flashed the list and could land on top of the NEXT action —
  // marking one item read would quietly undo the one archived a moment later.
  // A reload only happens when a write fails and local state may be wrong.
  const patchLocal = (ids, patch) =>
    setItems((cur) => cur.map((n) => ids.includes(n.id) ? { ...n, ...patch } : n));

  const act = async (fn, ids, patch, failMsg) => {
    setBusy(true);
    patchLocal(ids, patch);
    try { await fn(); }
    catch (e) {
      console.error(failMsg, e);
      onToast && onToast((e && e.message) || failMsg);
      await load();
    } finally { setBusy(false); }
  };

  const markRead = (n) => act(
    () => window.IPSEM_API.markNotificationsRead({ ids: [n.id] }),
    [n.id], { readAt: new Date().toISOString() }, 'Could not mark as read',
  );

  const markAllRead = () => act(
    () => window.IPSEM_API.markNotificationsRead({ recipient: me }),
    unread.map((n) => n.id), { readAt: new Date().toISOString() }, 'Could not mark all read',
  );

  const archiveOne = (n) => act(
    () => window.IPSEM_API.archiveNotifications({ ids: [n.id] }),
    [n.id], { archivedAt: new Date().toISOString(), readAt: n.readAt || new Date().toISOString() },
    'Could not archive',
  );

  const restoreOne = (n) => act(
    () => window.IPSEM_API.archiveNotifications({ ids: [n.id], restore: true }),
    [n.id], { archivedAt: null }, 'Could not restore',
  );

  const archiveAllRead = () => {
    const ids = inbox.filter((n) => n.readAt).map((n) => n.id);
    if (!ids.length) { onToast && onToast('Nothing read to archive'); return; }
    return act(
      () => window.IPSEM_API.archiveNotifications({ ids }),
      ids, { archivedAt: new Date().toISOString() }, 'Could not archive',
    );
  };

  // Catch mentions written in notes before this feature existed, or any that
  // failed to raise at the time. Idempotent — nothing is ever duplicated.
  const rescan = async () => {
    setBusy(true);
    try {
      const res = await window.IPSEM_API.backfillNotifications();
      await load();
      const made = (res && res.created) || 0;
      onToast && onToast(made
        // req() camelises the response, so the key is notesScanned — reading
        // notes_scanned made this always report "0 notes".
        ? `Found ${made} missed mention${made === 1 ? '' : 's'} in ${res.notesScanned || 0} notes`
        : `No missed mentions — ${(res && res.notesScanned) || 0} notes scanned`);
    } catch (e) {
      console.error('backfill failed:', e);
      onToast && onToast((e && e.message) || 'Could not scan notes');
    } finally {
      setBusy(false);
    }
  };

  const openBrand = (n) => {
    if (!n.readAt) window.IPSEM_API.markNotificationsRead({ ids: [n.id] }).catch(() => {});
    if (n.brandId) onNavigate('research', n.brandId);
  };


  if (!me) {
    return (
      <div className="page page-cap">
        <SectionHeader eyebrow="Workspace" title="Notifications" />
        <Card lg>
          <div className="text-2 text-sm" style={{ lineHeight: 1.6 }}>
            We could not work out which team member you are. Notifications are addressed
            to <strong>{ASSIGNEE_NAMES.join(', ')}</strong>, and your profile name and email
            match none of them. Click your avatar at the bottom of the sidebar and set your
            full name so it starts with your first name as the team writes it.
          </div>
        </Card>
      </div>
    );
  }

  return (
    <div className="page page-cap">
      <SectionHeader
        eyebrow="Workspace"
        title="Notifications"
        sub={`Every comment your teammates write on a brand, plus anything tagged @${me}. Times are London. Read it, open the brand, then archive it to clear your queue.`}
        right={
          <>
            <button className="btn" onClick={load} disabled={busy || loading}>
              <window.I.refresh size={14} className={loading ? 'spin' : ''} />
              Refresh
            </button>
            <button
              className="btn"
              onClick={rescan}
              disabled={busy || loading}
              title="Scan every brand note for @mentions and raise any that never became a notification. Safe to run repeatedly."
            >
              <window.I.at size={14} />
              Scan notes for mentions
            </button>
            {unread.length ? (
              <button className="btn" onClick={markAllRead} disabled={busy}>
                <window.I.check size={14} />
                Mark all read
              </button>
            ) : null}
            {tab === 'inbox' && inbox.some((n) => n.readAt) ? (
              <button className="btn" onClick={archiveAllRead} disabled={busy}>
                <window.I.inbox size={14} />
                Archive read
              </button>
            ) : null}
          </>
        }
      />

      <div className="row gap-2" style={{ marginBottom: 14 }}>
        <div className="toggle-group">
          <button className={tab === 'inbox' ? 'is-active' : ''} onClick={() => setTab('inbox')}>
            Inbox ({inbox.length}){unread.length ? ` · ${unread.length} new` : ''}
          </button>
          <button className={tab === 'archived' ? 'is-active' : ''} onClick={() => setTab('archived')}>
            Archived ({archived.length})
          </button>
        </div>
      </div>

      {loading && !items.length ? (
        <Card><div className="empty">Loading…</div></Card>
      ) : shown.length === 0 ? (
        <Card>
          <div className="empty">
            {tab === 'archived'
              ? 'Nothing archived yet.'
              : `No notifications. Any comment a teammate writes on a brand lands here, and being tagged @${me} is flagged as a mention.`}
          </div>
        </Card>
      ) : (
        <div className="col gap-2">
          {shown.map((n) => (
            <Card
              key={n.id}
              style={{
                borderColor: !n.readAt ? 'var(--accent)' : 'var(--hairline)',
                background: !n.readAt ? 'var(--accent-soft-bg)' : 'var(--card)',
              }}
            >
              <div className="row gap-3" style={{ alignItems: 'flex-start', flexWrap: 'wrap' }}>
                <Avatar initials={initialsFor(authorLabel(n.actor))} size={30} />
                <div className="grow" style={{ minWidth: 200 }}>
                  <div className="row gap-2" style={{ alignItems: 'center', flexWrap: 'wrap' }}>
                    {/* Same person, one name: notifications raised before the
                        writer set a profile name carry their email here. */}
                    <span className="text-sm" style={{ fontWeight: 600 }}>{n.actor ? authorLabel(n.actor) : 'Someone'}</span>
                    <span className="text-sm text-3">
                      {n.kind === 'comment' ? 'commented on' : 'mentioned you on'}
                    </span>
                    {n.brandId ? (
                      <button
                        className="text-sm"
                        onClick={() => openBrand(n)}
                        style={{ background: 'transparent', border: 0, padding: 0, cursor: 'pointer', color: 'var(--accent)', fontWeight: 600 }}
                      >
                        {n.brandName || n.brandId}
                      </button>
                    ) : <span className="text-sm" style={{ fontWeight: 600 }}>{n.brandName || '—'}</span>}
                    {!n.readAt ? <Pill kind="accent">New</Pill> : null}
                    {/* Pinned to London so everyone quotes the same clock;
                        hovering still shows the reader their own time. */}
                    <TimeStamp iso={n.createdAt} mode="both" tz={NOTIFICATION_TZ}
                               className="right text-xs text-3 mono" />
                  </div>
                  <div className="text-sm text-2" style={{ marginTop: 6, lineHeight: 1.55 }}>
                    <MentionText text={n.body} />
                  </div>
                  <div className="row gap-2" style={{ marginTop: 10, flexWrap: 'wrap' }}>
                    {n.brandId ? (
                      <button className="btn btn-sm" onClick={() => openBrand(n)}>
                        Open brand
                        <window.I.arrowRight size={12} />
                      </button>
                    ) : null}
                    {!n.readAt ? (
                      <button className="btn btn-sm" onClick={() => markRead(n)} disabled={busy}>
                        <window.I.check size={12} />
                        Mark read
                      </button>
                    ) : null}
                    {n.archivedAt ? (
                      <button className="btn btn-sm" onClick={() => restoreOne(n)} disabled={busy}>
                        <window.I.refresh size={12} />
                        Restore to inbox
                      </button>
                    ) : (
                      <button className="btn btn-sm" onClick={() => archiveOne(n)} disabled={busy}>
                        <window.I.inbox size={12} />
                        Archive
                      </button>
                    )}
                  </div>
                </div>
              </div>
            </Card>
          ))}
        </div>
      )}
    </div>
  );
}

window.NotificationsPage = NotificationsPage;
