// Global notifications: bell with unread badge, dropdown, and WS toasts for
// every lifecycle transition (§11.1).
import { api, toast } from '/static/js/api.js';
import { subscribe, onPollFallback } from '/static/js/ws.js';

if (document.body.dataset.loggedIn === '1') {
  const bell = document.getElementById('nav-bell');
  const badge = document.getElementById('nav-bell-count');
  const panel = document.getElementById('notif-panel');
  const list = document.getElementById('notif-list');

  const esc = (s) => String(s ?? '').replace(/[&<>"']/g, (c) => ({
    '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;',
  }[c]));

  async function refresh() {
    try {
      const res = await api('GET', '/api/v1/notifications?limit=15');
      badge.textContent = res.unread > 0 ? String(res.unread) : '';
      badge.hidden = res.unread === 0;
      list.replaceChildren(...res.notifications.map((n) => {
        const li = document.createElement('li');
        li.innerHTML = `<a href="${esc(n.link || '#')}">
          <strong>${esc(n.title)}</strong>${n.readAt ? '' : ' <span class="badge accent">new</span>'}<br>
          <span class="muted">${esc(n.body || '')}</span></a>`;
        return li;
      }));
      if (!res.notifications.length) {
        list.innerHTML = '<li class="muted">No notifications.</li>';
      }
    } catch (e) { /* signed out or transient */ }
  }

  bell.addEventListener('click', async () => {
    panel.hidden = !panel.hidden;
    if (!panel.hidden) {
      await refresh();
      try { await api('POST', '/api/v1/notifications/read', { ids: [] }); } catch (e) { /* ignore */ }
      badge.hidden = true;
      badge.textContent = '';
    }
  });
  document.addEventListener('click', (e) => {
    if (!panel.hidden && !panel.contains(e.target) && e.target !== bell) panel.hidden = true;
  });

  subscribe('notifications', (event, n) => {
    if (event === 'notification' && n) {
      toast(n.title, 'ok');
      refresh();
    }
  });
  onPollFallback(refresh);
  refresh();
}
