const NOTIFICATION_SETTINGS_KEY = 'seamenese_notification_settings_v1';
const PUSH_PROMPT_DISMISSED_KEY = 'seamenese_push_prompt_dismissed_v1';
const PUSH_LAST_SYNC_KEY = 'seamenese_push_last_sync_v1';
const PUSH_PENDING_ENABLE_KEY = 'seamenese_push_pending_enable_v1';
const PUSH_RESYNC_INTERVAL_MS = 24 * 60 * 60 * 1000;

function getCachedEffectivePermission() {
  if (typeof window === 'undefined') return 'unsupported';
  if (window.__seameneseEffectivePermission) return window.__seameneseEffectivePermission;
  return 'Notification' in window ? window.Notification.permission : 'unsupported';
}

function loadNotificationSettings() {
  try {
    const raw = JSON.parse(localStorage.getItem(NOTIFICATION_SETTINGS_KEY) || '{}');
    const soundEnabled = typeof raw?.soundEnabled === 'boolean' ? raw.soundEnabled : true;
    const rawDesktop = typeof raw?.desktopEnabled === 'boolean' ? raw.desktopEnabled : false;
    const perm = getCachedEffectivePermission();
    const desktopEnabled = perm === 'granted' ? rawDesktop : false;
    return {
      soundEnabled,
      desktopEnabled,
    };
  } catch {
    return { soundEnabled: true, desktopEnabled: false };
  }
}

function saveNotificationSettings(patch) {
  let raw = {};
  try {
    raw = JSON.parse(localStorage.getItem(NOTIFICATION_SETTINGS_KEY) || '{}') || {};
  } catch {}
  const prev = loadNotificationSettings();
  const next = {
    soundEnabled: typeof raw?.soundEnabled === 'boolean' ? raw.soundEnabled : prev.soundEnabled,
    desktopEnabled: typeof raw?.desktopEnabled === 'boolean' ? raw.desktopEnabled : prev.desktopEnabled,
    ...(patch || {}),
  };
  try {
    localStorage.setItem(NOTIFICATION_SETTINGS_KEY, JSON.stringify(next));
  } catch {}
  const effective = {
    soundEnabled: next.soundEnabled,
    desktopEnabled: getCachedEffectivePermission() === 'granted' ? Boolean(next.desktopEnabled) : false,
  };
  if (typeof window !== 'undefined') {
    window.dispatchEvent(new CustomEvent('seamenese-notification-settings-changed', { detail: effective }));
  }
  return effective;
}

function urlBase64ToUint8Array(base64String) {
  const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
  const rawData = window.atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  for (let i = 0; i < rawData.length; i += 1) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

function detectNotificationEnvironment(customUa) {
  if (typeof window === 'undefined' && !customUa) {
    return {
      isStandalone: false,
      isIos: false,
      isAndroid: false,
      isMac: false,
      isWindows: false,
      isLinux: false,
      browserKey: 'other',
      browserName: 'Browser',
      supportsNotification: false,
      supportsPush: false,
      permission: 'unsupported',
    };
  }
  const ua = typeof customUa === 'string' ? customUa : (window.navigator?.userAgent || '');
  const brands = (typeof customUa !== 'string' && window.navigator?.userAgentData?.brands) || [];
  const brandStr = brands.map(b => b.brand || '').join(' ');

  const isIos = /iPad|iPhone|iPod/.test(ua) || (typeof customUa !== 'string' && window.navigator?.platform === 'MacIntel' && window.navigator?.maxTouchPoints > 1);
  const isAndroid = /Android/i.test(ua);
  const isMac = !isIos && /Macintosh|Mac OS X/i.test(ua);
  const isWindows = /Windows/i.test(ua);
  const isLinux = !isAndroid && /Linux/i.test(ua);

  const isOperaGx = /OPRGX|Opera GX/i.test(ua) || /Opera GX/i.test(brandStr);
  const isOpera = isOperaGx || /OPR\/|OPT\/|OPiOS\/|Opera/i.test(ua) || /Opera/i.test(brandStr);
  const isEdge = /Edg\/|EdgiOS\/|EdgA\//i.test(ua) || /Microsoft Edge/i.test(brandStr);
  const isSamsung = /SamsungBrowser\//i.test(ua);
  const isVivaldi = /Vivaldi\//i.test(ua);
  const isFirefox = /Firefox\/|FxiOS\//i.test(ua);
  const isBrave = (typeof customUa !== 'string' && Boolean(window.navigator?.brave)) || /Brave/i.test(ua) || /Brave/i.test(brandStr);
  const isIosChrome = /CriOS\//i.test(ua);
  const isSafari = !isOpera && !isEdge && !isSamsung && !isVivaldi && !isFirefox && !isBrave && !isIosChrome && /Safari\//i.test(ua) && !/Chrome\/|Chromium\//i.test(ua);
  const isChrome = !isOpera && !isEdge && !isSamsung && !isVivaldi && !isFirefox && !isBrave && !isSafari && (/Chrome\/|Chromium\/|CriOS\//i.test(ua));

  let browserKey = 'other';
  let browserName = 'Browser';
  if (isOperaGx) { browserKey = 'opera-gx'; browserName = 'Opera GX'; }
  else if (isOpera) { browserKey = 'opera'; browserName = 'Opera'; }
  else if (isFirefox) { browserKey = 'firefox'; browserName = 'Firefox'; }
  else if (isEdge) { browserKey = 'edge'; browserName = 'Microsoft Edge'; }
  else if (isSamsung) { browserKey = 'samsung'; browserName = 'Samsung Internet'; }
  else if (isVivaldi) { browserKey = 'vivaldi'; browserName = 'Vivaldi'; }
  else if (isBrave) { browserKey = 'brave'; browserName = 'Brave'; }
  else if (isSafari) { browserKey = 'safari'; browserName = 'Safari'; }
  else if (isChrome || isIosChrome) { browserKey = 'chrome'; browserName = 'Chrome'; }

  const isStandalone = typeof customUa === 'string'
    ? false
    : Boolean(
        window.matchMedia?.('(display-mode: standalone)')?.matches ||
        window.matchMedia?.('(display-mode: window-controls-overlay)')?.matches ||
        window.matchMedia?.('(display-mode: minimal-ui)')?.matches ||
        window.matchMedia?.('(display-mode: fullscreen)')?.matches ||
        window.navigator?.standalone === true ||
        (typeof document !== 'undefined' && document.referrer?.startsWith('android-app://'))
      );

  const supportsNotification = typeof window !== 'undefined' && 'Notification' in window;
  const supportsPush = typeof navigator !== 'undefined' && 'serviceWorker' in navigator && typeof window !== 'undefined' && 'PushManager' in window;
  const permission = supportsNotification ? getCachedEffectivePermission() : 'unsupported';
  return {
    isStandalone,
    isIos,
    isAndroid,
    isMac,
    isWindows,
    isLinux,
    isOperaGx,
    isOpera,
    isEdge,
    isSamsung,
    isVivaldi,
    isFirefox,
    isBrave,
    isSafari,
    isChrome,
    browserKey,
    browserName,
    supportsNotification,
    supportsPush,
    permission,
  };
}

function getWebAppInstallGuide(env = detectNotificationEnvironment()) {
  if (env.isStandalone) {
    return null;
  }
  if (env.isIos) {
    if (env.isSafari) {
      return {
        title: 'Install on iPhone / iPad (Safari)',
        summary: 'Add Seamenese to your Home Screen to use it as a full-screen app and enable iOS push notifications.',
        steps: [
          'Tap the Share (📤) button in the Safari toolbar.',
          'Scroll down the share sheet and tap "Add to Home Screen".',
          'Tap "Add" in the top-right corner, then open Seamenese from your Home Screen.',
        ],
      };
    }
    return {
      title: `Install on iPhone / iPad (${env.browserName})`,
      summary: `Add Seamenese to your Home Screen from ${env.browserName} to use it as a standalone app and unlock iOS push notifications.`,
      steps: [
        'Tap the Share (📤) icon in the address bar (or browser menu).',
        'Tap "Add to Home Screen" in the share menu.',
        'Tap "Add", then open Seamenese from your Home Screen.',
      ],
    };
  }

  if (env.isAndroid) {
    if (env.isFirefox) {
      return {
        title: 'Install on Android (Firefox)',
        summary: 'Add Seamenese to your Android Home Screen from Firefox.',
        steps: [
          'Tap the ⋮ menu button next to the Firefox address bar.',
          'Tap "Install" (or "Add app to Home screen").',
          'Confirm to add the Seamenese Web App to your launcher.',
        ],
      };
    }
    if (env.isOpera) {
      return {
        title: `Install on Android (${env.browserName})`,
        summary: `Install Seamenese to your Home Screen from ${env.browserName}.`,
        steps: [
          'Tap the ⋮ menu (or Opera icon) in the browser bar.',
          'Tap "Add to Home screen" (or "Install app").',
          'Confirm to add Seamenese to your Home Screen.',
        ],
      };
    }
    if (env.isSamsung) {
      return {
        title: 'Install on Android (Samsung Internet)',
        summary: 'Install Seamenese as a standalone Web App from Samsung Internet.',
        steps: [
          'Tap the install icon (⬇️+) in the address bar, or open the ≡ menu.',
          'Select "Add page to" → "Home screen" (or "App screen").',
        ],
      };
    }
    return {
      title: `Install on Android (${env.browserName})`,
      summary: `Install Seamenese as a standalone Android app in ${env.browserName} for quick launch and background push alerts.`,
      steps: [
        `Tap the ⋮ menu in the top-right corner of ${env.browserName}.`,
        'Tap "Install app" (or "Add to Home screen").',
        'Tap "Install" to add Seamenese to your app drawer.',
      ],
    };
  }

  // Desktop browsers
  if (env.isFirefox) {
    return {
      title: 'Web App on Firefox Desktop',
      summary: 'Desktop Firefox does not include built-in standalone Web App installation by default (push notifications still work right inside Firefox!).',
      steps: [
        'To receive push notifications in Firefox right now, click "Setup Notifications" above.',
        'If you want a standalone desktop window in Firefox, you can use the "Progressive Web Apps for Firefox" add-on, or open Seamenese in Chrome, Edge, or Brave.',
      ],
    };
  }
  if (env.isOperaGx) {
    return {
      title: 'Web App on Opera GX',
      summary: 'Opera GX does not always show a standalone Web App installer in the address bar (push notifications still work directly inside Opera GX!).',
      steps: [
        'To get background alerts in Opera GX right now, click "Setup Notifications" above.',
        'To keep Seamenese handy in Opera GX: right-click the tab → "Pin tab", or add it to your GX Sidebar.',
        'If you want a standalone desktop app window, open Seamenese in Chrome, Edge, or Brave and click the install icon in the address bar.',
      ],
    };
  }
  if (env.isOpera) {
    return {
      title: 'Install on Desktop (Opera)',
      summary: 'Install or pin Seamenese in Opera Desktop.',
      steps: [
        'If your Opera build shows the install icon (📲) on the right side of the address bar, click it and choose "Install".',
        'Otherwise, right-click the tab → "Pin tab", or open Seamenese in Chrome or Edge to install a standalone desktop window.',
      ],
    };
  }
  if (env.isSafari && env.isMac) {
    return {
      title: 'Install on Mac (Safari)',
      summary: 'Add Seamenese to your macOS Dock as a standalone Web App.',
      steps: [
        'In the top Mac menu bar, click File → "Add to Dock…" (or click Share 📤 → "Add to Dock").',
        'Click "Add" to launch Seamenese from your Dock with push notification support.',
      ],
    };
  }
  if (env.isEdge) {
    return {
      title: 'Install on Desktop (Microsoft Edge)',
      summary: 'Install Seamenese as a standalone desktop app in Microsoft Edge.',
      steps: [
        'Click the "App available" (📲) icon on the right side of the Edge address bar.',
        'Or open the ⋯ menu (top-right) → Apps → "Install this site as an app".',
      ],
    };
  }
  return {
    title: `Install on Desktop (${env.browserName})`,
    summary: `Install Seamenese as a standalone desktop app in ${env.browserName}.`,
    steps: [
      'Click the Install icon (📲 / monitor with down-arrow) on the right side of the address bar.',
      `Or open the ⋮ menu in the top-right corner of ${env.browserName} → "Cast, save, and share" → "Install page as app…".`,
    ],
  };
}

function getBlockedNotificationHelp(env = detectNotificationEnvironment()) {
  if (env.isIos && !env.isStandalone) {
    return `To get notifications on iPhone or iPad: tap Share (📤) in ${env.browserName} → "Add to Home Screen", then open the Seamenese Web App from your Home Screen and tap Setup Notifications.`;
  }
  if (env.isStandalone && env.isIos) {
    return 'Notifications are currently turned off for this Web App. Open your iPhone/iPad Settings → Notifications → Seamenese and turn Allow Notifications ON. When you return here, setup will finish automatically.';
  }
  if (env.isStandalone && env.isAndroid) {
    return 'Notifications are currently turned off for this Web App. Long-press the Seamenese app icon on your Home Screen → open ⚙️ Site settings (and ⓘ App info) → Notifications → turn Allow notifications ON. When you return here, setup will finish automatically.';
  }
  if (env.isStandalone) {
    return 'Notifications are currently turned off for this Web App. Click the ⋮ (or ⋯) menu at the top of the app window → App info / App settings → set Notifications to Allow, then return here or tap Retry Setup.';
  }
  if (env.isFirefox) {
    return 'Notifications are blocked in Firefox. Click the lock / permissions icon (🔒) on the left of the address bar → next to "Send Notifications", clear the block (✕), then tap Retry Setup.';
  }
  if (env.isOperaGx || env.isOpera) {
    return `Notifications are blocked in ${env.browserName}. Click the lock / site settings icon on the left of the address bar → set Notifications to Allow, then tap Retry Setup.`;
  }
  if (env.isSafari) {
    return 'Notifications are blocked in Safari. Open Safari → Settings… → Websites → Notifications, set this site to Allow, then tap Retry Setup.';
  }
  if (env.isEdge) {
    return 'Notifications are blocked in Microsoft Edge. Click the lock / tune icon on the left of the address bar → Permissions for this site → set Notifications to Allow, then tap Retry Setup.';
  }
  return `Notifications are blocked in ${env.browserName}. Click the tune / site info icon on the left of the address bar → set Notifications to Allow (or Reset permission), then tap Retry Setup.`;
}

async function queryEffectiveNotificationPermission() {
  if (typeof window === 'undefined' || !('Notification' in window)) {
    window.__seameneseEffectivePermission = 'unsupported';
    return 'unsupported';
  }
  let perm = window.Notification.permission;
  let permApiState = null;
  let pushApiState = null;

  try {
    if (navigator.permissions?.query) {
      const status = await navigator.permissions.query({ name: 'notifications' });
      permApiState = status?.state || null;
    }
  } catch {}

  try {
    if ('serviceWorker' in navigator && 'PushManager' in window) {
      const reg = await navigator.serviceWorker.getRegistration();
      if (reg?.pushManager?.permissionState) {
        pushApiState = await reg.pushManager.permissionState({ userVisibleOnly: true });
      }
    }
  } catch {}

  // Prefer live OS/Permissions API state over potentially cached window.Notification.permission on Android WebAPKs
  if (permApiState === 'denied' || pushApiState === 'denied') {
    perm = 'denied';
  } else if (permApiState === 'granted' || pushApiState === 'granted') {
    perm = 'granted';
  } else if ((permApiState === 'prompt' || pushApiState === 'prompt') && perm === 'granted') {
    perm = 'default';
  }

  window.__seameneseEffectivePermission = perm;
  return perm;
}

async function verifyNotificationPermissionAndSubscription() {
  if (typeof window === 'undefined' || !('Notification' in window)) {
    saveNotificationSettings({ desktopEnabled: false });
    return { enabled: false, permission: 'unsupported' };
  }

  let raw = {};
  try {
    raw = JSON.parse(localStorage.getItem(NOTIFICATION_SETTINGS_KEY) || '{}') || {};
  } catch {}
  const wantedDesktop = Boolean(raw?.desktopEnabled);
  const pendingManualEnable = localStorage.getItem(PUSH_PENDING_ENABLE_KEY) === '1';

  const perm = await queryEffectiveNotificationPermission();

  if (perm !== 'granted') {
    if (wantedDesktop) {
      try {
        localStorage.setItem(PUSH_PENDING_ENABLE_KEY, '1');
      } catch {}
    }
    saveNotificationSettings({ desktopEnabled: false });
    return { enabled: false, permission: perm };
  }

  // If the user previously tried to enable notifications (or had them enabled before turning them off in phone settings)
  // and has now manually enabled them in OS / Site settings, automatically complete push setup!
  if (pendingManualEnable || wantedDesktop) {
    try {
      const reg = await navigator.serviceWorker?.getRegistration();
      const existingSub = await reg?.pushManager?.getSubscription();
      if (pendingManualEnable || !existingSub) {
        const pushRes = await ensurePushSubscription({
          sendTest: pendingManualEnable,
          forceResubscribe: pendingManualEnable,
        });
        if (pushRes.subscribed) {
          try {
            localStorage.removeItem(PUSH_PENDING_ENABLE_KEY);
          } catch {}
          const updated = saveNotificationSettings({ desktopEnabled: true });
          window.dispatchEvent(new CustomEvent('seamenese-notification-auto-restored', {
            detail: {
              ...updated,
              message: 'Push notifications are active! A confirmation notification has been sent to your device.',
            },
          }));
          return { enabled: true, permission: 'granted', autoRestored: true };
        }
      }
    } catch {}
  }

  return {
    enabled: loadNotificationSettings().desktopEnabled,
    permission: 'granted',
  };
}

async function ensurePushSubscription({ sendTest = false, vapidPublicKey = '', forceResubscribe = false } = {}) {
  if (typeof navigator === 'undefined' || !('serviceWorker' in navigator) || !('PushManager' in window)) {
    return { subscribed: false, reason: 'unsupported' };
  }
  const reg = await navigator.serviceWorker.register('/service-worker.js');
  await navigator.serviceWorker.ready;
  if (!reg.pushManager) {
    return { subscribed: false, reason: 'no-push-manager' };
  }
  let publicKey = String(vapidPublicKey || window.__seameneseVapidPublicKey || '').trim();
  if (!publicKey) {
    const keyRes = await communityRequest('/api/push/vapid-public-key');
    publicKey = String(keyRes?.publicKey || '').trim();
    if (publicKey) window.__seameneseVapidPublicKey = publicKey;
  }
  if (!publicKey) {
    return { subscribed: false, reason: 'missing-vapid-key' };
  }
  const appServerKey = urlBase64ToUint8Array(publicKey);
  let sub = await reg.pushManager.getSubscription();
  if (sub && forceResubscribe) {
    await sub.unsubscribe().catch(() => {});
    sub = null;
  } else if (sub && sub.options?.applicationServerKey) {
    const existingKey = new Uint8Array(sub.options.applicationServerKey);
    const sameKey = existingKey.length === appServerKey.length && existingKey.every((b, i) => b === appServerKey[i]);
    if (!sameKey) {
      await sub.unsubscribe().catch(() => {});
      sub = null;
    }
  }
  if (!sub) {
    sub = await reg.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: appServerKey,
    });
  }
  const subJson = sub.toJSON();
  await communityRequest('/api/push/subscribe', {
    method: 'POST',
    body: JSON.stringify({
      ...subJson,
      test: Boolean(sendTest),
    }),
  });
  try {
    localStorage.setItem(PUSH_LAST_SYNC_KEY, String(Date.now()));
  } catch {}
  if (typeof window !== 'undefined') {
    window.dispatchEvent(new CustomEvent('seamenese-push-subscription-changed', { detail: { subscribed: true } }));
  }
  return { subscribed: true, endpoint: sub.endpoint };
}

async function syncPushSubscriptionQuietly(vapidPublicKey = '') {
  try {
    const check = await verifyNotificationPermissionAndSubscription();
    if (!check.enabled || check.permission !== 'granted') return;
    const env = detectNotificationEnvironment();
    if (!env.supportsNotification || !env.supportsPush) return;
    if (vapidPublicKey) window.__seameneseVapidPublicKey = vapidPublicKey;

    const reg = await navigator.serviceWorker.register('/service-worker.js');
    await navigator.serviceWorker.ready;
    if (!reg.pushManager) return;

    const existing = await reg.pushManager.getSubscription();
    const lastSync = Number(localStorage.getItem(PUSH_LAST_SYNC_KEY) || '0');
    if (existing && Date.now() - lastSync < PUSH_RESYNC_INTERVAL_MS) {
      return;
    }
    await ensurePushSubscription({ sendTest: false, vapidPublicKey });
  } catch {}
}

async function setupPushNotifications({ sendTest = true } = {}) {
  try {
    localStorage.removeItem(PUSH_PROMPT_DISMISSED_KEY);
    localStorage.setItem(PUSH_PENDING_ENABLE_KEY, '1');
  } catch {}
  const env = detectNotificationEnvironment();
  if (env.isIos && !env.isStandalone && !env.supportsNotification) {
    return {
      ok: false,
      state: 'ios-browser',
      permission: 'unsupported',
      message: getBlockedNotificationHelp(env),
    };
  }
  if (!env.supportsNotification) {
    return {
      ok: false,
      state: 'unsupported',
      permission: 'unsupported',
      message: getBlockedNotificationHelp(env),
    };
  }

  let perm = window.Notification.permission;
  try {
    // Always invoke requestPermission() inside the user gesture handler so re-invoking works if permission was reset or on Web Apps
    perm = await window.Notification.requestPermission();
  } catch {
    perm = window.Notification.permission;
  }

  const effectivePerm = await queryEffectiveNotificationPermission();
  if (effectivePerm === 'granted') {
    perm = 'granted';
  } else if (effectivePerm === 'denied') {
    perm = 'denied';
  }

  // On Android WebApps, even if window.Notification.permission was cached as 'denied' on the current tab,
  // if the user just turned notifications ON in OS/Site settings, pushManager.subscribe() can succeed.
  if (env.supportsPush) {
    try {
      const pushRes = await ensurePushSubscription({ sendTest, forceResubscribe: true });
      if (pushRes.subscribed) {
        window.__seameneseEffectivePermission = 'granted';
        try {
          localStorage.removeItem(PUSH_PENDING_ENABLE_KEY);
        } catch {}
        saveNotificationSettings({ desktopEnabled: true });
        return {
          ok: true,
          state: 'granted',
          permission: 'granted',
          pushSubscribed: true,
          message: sendTest
            ? 'Push notifications are active! A confirmation notification has been sent to your device.'
            : 'Push notifications are active on this device.',
        };
      }
    } catch {
      saveNotificationSettings({ desktopEnabled: false });
      return {
        ok: false,
        state: 'denied',
        permission: 'denied',
        message: getBlockedNotificationHelp({ ...env, permission: 'denied' }),
      };
    }
  }

  if (perm !== 'granted') {
    saveNotificationSettings({ desktopEnabled: false });
    return {
      ok: false,
      state: perm === 'denied' ? 'denied' : 'default',
      permission: perm,
      message: getBlockedNotificationHelp({ ...env, permission: perm }),
    };
  }

  try {
    localStorage.removeItem(PUSH_PENDING_ENABLE_KEY);
  } catch {}
  saveNotificationSettings({ desktopEnabled: true });
  if (sendTest) {
    sendDesktopNotification({
      id: `seamenese-desktop-test-${Date.now()}`,
      title: 'Seamenese Notifications Enabled',
      body: 'You will now receive alerts for mentions, replies, and scheduled SRS reviews.',
    });
  }
  return {
    ok: true,
    state: 'granted',
    permission: 'granted',
    pushSubscribed: false,
    message: 'Notifications enabled for this device!',
  };
}

async function disablePushNotifications() {
  try {
    localStorage.removeItem(PUSH_PENDING_ENABLE_KEY);
  } catch {}
  saveNotificationSettings({ desktopEnabled: false });
  try {
    if ('serviceWorker' in navigator) {
      const reg = await navigator.serviceWorker.getRegistration();
      const sub = await reg?.pushManager?.getSubscription();
      if (sub) {
        const endpoint = sub.endpoint;
        await sub.unsubscribe().catch(() => {});
        await communityRequest('/api/push/unsubscribe', {
          method: 'POST',
          body: JSON.stringify({ endpoint }),
        }).catch(() => {});
      }
    }
    localStorage.removeItem(PUSH_LAST_SYNC_KEY);
  } catch {}
  if (typeof window !== 'undefined') {
    window.dispatchEvent(new CustomEvent('seamenese-push-subscription-changed', { detail: { subscribed: false } }));
  }
}

async function sendTestPushNotification() {
  const check = await verifyNotificationPermissionAndSubscription();
  if (check.permission !== 'granted') {
    return setupPushNotifications({ sendTest: true });
  }
  saveNotificationSettings({ desktopEnabled: true });
  try {
    await ensurePushSubscription({ sendTest: false });
    const res = await communityRequest('/api/push/test', { method: 'POST', body: JSON.stringify({}) });
    if (res?.sent > 0) {
      return { ok: true, message: 'Sent a test push notification to your device!' };
    }
  } catch {
    saveNotificationSettings({ desktopEnabled: false });
    return {
      ok: false,
      message: getBlockedNotificationHelp(detectNotificationEnvironment()),
    };
  }
  sendDesktopNotification({
    id: `seamenese-test-${Date.now()}`,
    title: 'Seamenese Test Notification',
    body: 'Notifications are working on your device!',
  });
  return { ok: true, message: 'Sent a test notification!' };
}

function openNotificationSetup() {
  try {
    localStorage.removeItem(PUSH_PROMPT_DISMISSED_KEY);
  } catch {}
  if (typeof window !== 'undefined') {
    window.dispatchEvent(new CustomEvent('seamenese-open-notification-setup'));
  }
}

function playNotificationSound(force = false) {
  const prefs = loadNotificationSettings();
  if (!force && !prefs.soundEnabled) return;
  try {
    const AudioCtx = window.AudioContext || window.webkitAudioContext;
    if (!AudioCtx) return;
    const ctx = new AudioCtx();
    const now = ctx.currentTime;
    const notes = [
      { freq: 659.25, t: 0.0, d: 0.14, gain: 0.11 },  // E5
      { freq: 987.77, t: 0.09, d: 0.18, gain: 0.12 }, // B5
      { freq: 1318.51, t: 0.19, d: 0.28, gain: 0.1 }, // E6
    ];
    notes.forEach(n => {
      const osc = ctx.createOscillator();
      const g = ctx.createGain();
      osc.type = 'sine';
      osc.frequency.setValueAtTime(n.freq, now + n.t);
      g.gain.setValueAtTime(0.0001, now + n.t);
      g.gain.exponentialRampToValueAtTime(n.gain, now + n.t + 0.015);
      g.gain.exponentialRampToValueAtTime(0.0001, now + n.t + n.d);
      osc.connect(g);
      g.connect(ctx.destination);
      osc.start(now + n.t);
      osc.stop(now + n.t + n.d + 0.02);
    });
  } catch {}
}

function sendDesktopNotification(item) {
  if (!item) return;
  const prefs = loadNotificationSettings();
  if (!prefs.desktopEnabled) return;
  if (typeof window === 'undefined' || typeof window.Notification === 'undefined') return;
  if (window.Notification.permission !== 'granted') return;

  const cleanBody = item.kind === 'srs' && window.SeameneseCommunityModel?.formatSrsNotificationBody && !/^It is time to review an? [a-z]+\.$/i.test(String(item.body || ''))
    ? window.SeameneseCommunityModel.formatSrsNotificationBody(item.reference || item.body)
    : (item.body || 'New notification in Seamenese');

  const title = item.title || 'Seamenese Lexicon';
  const options = {
    body: cleanBody,
    tag: item.id || item.reference || 'seamenese-notice',
    renotify: false,
  };

  try {
    if (navigator.serviceWorker?.controller) {
      navigator.serviceWorker.ready
        .then(reg => reg.showNotification(title, options))
        .catch(() => {
          const n = new window.Notification(title, options);
          n.onclick = () => { try { window.focus(); n.close(); } catch {} };
        });
      return;
    }
    const n = new window.Notification(title, options);
    n.onclick = () => { try { window.focus(); n.close(); } catch {} };
  } catch {}
}

if (typeof window !== 'undefined') {
  window.__seameneseDeferredInstallPrompt = null;
  window.addEventListener('beforeinstallprompt', (e) => {
    e.preventDefault();
    window.__seameneseDeferredInstallPrompt = e;
    window.dispatchEvent(new CustomEvent('seamenese-pwa-install-available'));
  });
  window.addEventListener('appinstalled', () => {
    window.__seameneseDeferredInstallPrompt = null;
    window.dispatchEvent(new CustomEvent('seamenese-pwa-installed'));
  });
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
      navigator.serviceWorker.register('/service-worker.js').catch(() => {});
    });
  }
  window.addEventListener('focus', () => {
    verifyNotificationPermissionAndSubscription().catch(() => {});
  });
  document.addEventListener('visibilitychange', () => {
    if (!document.hidden) {
      verifyNotificationPermissionAndSubscription().catch(() => {});
    }
  });
  if (navigator.permissions?.query) {
    navigator.permissions.query({ name: 'notifications' })
      .then(status => {
        status.onchange = () => {
          verifyNotificationPermissionAndSubscription().catch(() => {});
        };
      })
      .catch(() => {});
  }
  Object.assign(window, {
    loadNotificationSettings,
    saveNotificationSettings,
    playNotificationSound,
    sendDesktopNotification,
    detectNotificationEnvironment,
    getWebAppInstallGuide,
    getBlockedNotificationHelp,
    verifyNotificationPermissionAndSubscription,
    setupPushNotifications,
    disablePushNotifications,
    sendTestPushNotification,
    openNotificationSetup,
  });
}

function NotificationSetupPrompt() {
  const [visible, setVisible] = React.useState(false);
  const [state, setState] = React.useState('default'); // 'default' | 'ios-browser' | 'denied' | 'granted' | 'unsupported'
  const [busy, setBusy] = React.useState(false);
  const [statusMsg, setStatusMsg] = React.useState('');

  const refreshEnvState = React.useCallback(() => {
    const env = detectNotificationEnvironment();
    const prefs = loadNotificationSettings();
    if (env.isIos && !env.isStandalone && !env.supportsNotification) {
      setState('ios-browser');
    } else if (!env.supportsNotification) {
      setState('unsupported');
    } else if (env.permission === 'granted' && prefs.desktopEnabled) {
      setState('granted');
    } else if (env.permission === 'denied') {
      setState('denied');
    } else {
      setState('default');
    }
  }, []);

  React.useEffect(() => {
    refreshEnvState();
    const onOpenSetup = () => {
      refreshEnvState();
      setStatusMsg('');
      setVisible(true);
    };
    const onSettingsChanged = () => refreshEnvState();
    const onAutoRestored = (e) => {
      refreshEnvState();
      setState('granted');
      setStatusMsg(e?.detail?.message || 'Push notifications are active!');
    };
    window.addEventListener('seamenese-open-notification-setup', onOpenSetup);
    window.addEventListener('seamenese-notification-settings-changed', onSettingsChanged);
    window.addEventListener('seamenese-push-subscription-changed', onSettingsChanged);
    window.addEventListener('seamenese-notification-auto-restored', onAutoRestored);
    return () => {
      window.removeEventListener('seamenese-open-notification-setup', onOpenSetup);
      window.removeEventListener('seamenese-notification-settings-changed', onSettingsChanged);
      window.removeEventListener('seamenese-push-subscription-changed', onSettingsChanged);
      window.removeEventListener('seamenese-notification-auto-restored', onAutoRestored);
    };
  }, [refreshEnvState]);

  function dismiss() {
    try {
      localStorage.setItem(PUSH_PROMPT_DISMISSED_KEY, '1');
    } catch {}
    setVisible(false);
  }

  async function handleEnable() {
    setBusy(true);
    setStatusMsg('');
    try {
      const res = await setupPushNotifications({ sendTest: true });
      setState(res.state || (res.ok ? 'granted' : 'denied'));
      setStatusMsg(res.message || '');
    } catch (err) {
      setStatusMsg(err?.message || 'Could not complete notification setup.');
    } finally {
      setBusy(false);
    }
  }

  async function handleTestPush() {
    setBusy(true);
    setStatusMsg('');
    try {
      const res = await sendTestPushNotification();
      setStatusMsg(res.message || 'Test notification sent!');
    } catch (err) {
      setStatusMsg(err?.message || 'Could not send test notification.');
    } finally {
      setBusy(false);
    }
  }

  if (!visible) return null;
  const env = detectNotificationEnvironment();

  return (
    <div
      className="notification-setup-card"
      role="dialog"
      aria-label="Setup push notifications"
      style={{
        position: 'fixed',
        bottom: 20,
        right: 20,
        zIndex: 9999,
        maxWidth: 380,
        width: 'calc(100vw - 32px)',
        background: 'var(--bg-elev, #181614)',
        color: 'var(--fg, #f5f2eb)',
        border: '1px solid var(--rule, rgba(255,255,255,0.16))',
        borderRadius: 12,
        padding: '14px 16px',
        boxShadow: '0 14px 36px rgba(0,0,0,0.45)',
      }}
    >
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
        <div
          aria-hidden="true"
          style={{
            width: 34,
            height: 34,
            borderRadius: 8,
            background: 'rgba(217, 119, 6, 0.16)',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            fontSize: 18,
            flexShrink: 0,
          }}
        >
          🔔
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 13, marginBottom: 4 }}>
            {state === 'granted'
              ? 'Push Notifications Active'
              : state === 'ios-browser'
              ? 'Add to Home Screen for Push Alerts'
              : state === 'denied'
              ? 'Notifications Turned Off on Device'
              : 'Setup Push Notifications'}
          </div>
          <div style={{ fontSize: 12, lineHeight: 1.45, color: 'var(--fg-dim, #b8b2a6)' }}>
            {state === 'ios-browser' && (
              <span>
                To get push notifications on iPhone or iPad, first add Seamenese to your Home Screen (tap <strong>Share 📤 → Add to Home Screen</strong>), then open the app from your Home Screen and tap <strong>Setup Notifications</strong>.
              </span>
            )}
            {state === 'denied' && (
              <span>{getBlockedNotificationHelp(env)}</span>
            )}
            {state === 'default' && (
              <span>
                Get instant push alerts for Global Chat mentions, replies, and due SRS vocabulary reviews — even when the app is in the background.
              </span>
            )}
            {state === 'granted' && (
              <span>
                This {env.isStandalone ? 'Web App' : 'browser'} is subscribed to Seamenese push notifications.
              </span>
            )}
            {state === 'unsupported' && (
              <span>{getBlockedNotificationHelp(env)}</span>
            )}
          </div>

          {statusMsg && (
            <div
              className="mono"
              style={{
                marginTop: 8,
                padding: '6px 8px',
                borderRadius: 6,
                fontSize: 11,
                background: state === 'granted' ? 'rgba(16, 185, 129, 0.14)' : 'rgba(245, 158, 11, 0.14)',
                color: state === 'granted' ? '#34d399' : '#fbbf24',
              }}
            >
              {statusMsg}
            </div>
          )}

          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 12, flexWrap: 'wrap' }}>
            {(state === 'default' || state === 'denied') && (
              <button
                type="button"
                className="btn btn-primary"
                style={{ padding: '6px 12px', fontSize: 11 }}
                disabled={busy}
                onClick={handleEnable}
              >
                {busy ? 'Requesting…' : state === 'denied' ? '🔄 Retry Setup' : '🔔 Enable Push Notifications'}
              </button>
            )}
            {state === 'granted' && (
              <button
                type="button"
                className="btn btn-accent"
                style={{ padding: '6px 12px', fontSize: 11 }}
                disabled={busy}
                onClick={handleTestPush}
              >
                {busy ? 'Sending…' : '🔔 Send Test Notification'}
              </button>
            )}
            <button
              type="button"
              className="btn"
              style={{ padding: '6px 10px', fontSize: 11 }}
              onClick={dismiss}
            >
              {state === 'granted' ? 'Done' : 'Dismiss'}
            </button>
          </div>
        </div>
        <button
          type="button"
          className="gear-btn"
          aria-label="Close notification setup"
          onClick={dismiss}
          style={{ padding: '2px 6px', fontSize: 12 }}
        >
          ✕
        </button>
      </div>
    </div>
  );
}

if (typeof window !== 'undefined') {
  window.NotificationSetupPrompt = NotificationSetupPrompt;
}

function mergeWithLocalSceneNotifications(serverItems = []) {
  const localRaw = typeof window !== 'undefined' && window.loadLocalSceneNotifications
    ? window.loadLocalSceneNotifications()
    : [];
  if (!localRaw.length) return serverItems;
  const serverRefs = new Set(serverItems.map(i => i.reference).filter(Boolean));
  const serverSceneTimes = serverItems
    .filter(i => i.kind === 'scenes' && i.created_at)
    .map(i => new Date(i.created_at).getTime())
    .filter(Number.isFinite);
  const keptLocal = [];
  let pruned = false;
  for (const loc of localRaw) {
    const locTime = loc.created_at ? new Date(loc.created_at).getTime() : 0;
    const matchedOnServer =
      (loc.reference && serverRefs.has(loc.reference)) ||
      (locTime && serverSceneTimes.some(t => Math.abs(t - locTime) < 25_000));
    if (matchedOnServer) {
      pruned = true;
    } else {
      keptLocal.push(loc);
    }
  }
  if (pruned && typeof window !== 'undefined' && window.saveLocalSceneNotifications) {
    window.saveLocalSceneNotifications(keptLocal);
  }
  if (!keptLocal.length) return serverItems;
  return [...keptLocal, ...serverItems].sort((a, b) =>
    String(b.created_at || '').localeCompare(String(a.created_at || ''))
  );
}

function useNotifications({ ready, account, profileId, db }) {
  const [items, setItems] = React.useState(() => mergeWithLocalSceneNotifications([]));
  const [pushSubscribed, setPushSubscribed] = React.useState(false);
  const [error, setError] = React.useState('');
  const current = React.useRef({ account, profileId, db });
  current.current = { account, profileId, db };
  const generation = React.useRef(0);
  const knownIdsRef = React.useRef(null);

  const refresh = React.useCallback(async () => {
    const run = generation.current;
    // Immediately reflect any local scene notifications before network roundtrip finishes
    setItems(prev => {
      const serverOnly = prev.filter(i => !i.local_only);
      return mergeWithLocalSceneNotifications(serverOnly);
    });
    try {
      const result = await communityRequest('/api/notifications');
      if (generation.current === run) {
        if (result.vapid_public_key) {
          window.__seameneseVapidPublicKey = result.vapid_public_key;
        }
        setPushSubscribed(Boolean(result.push_subscribed));
        syncPushSubscriptionQuietly(result.vapid_public_key || '');
        const nextItems = mergeWithLocalSceneNotifications(result.items || []);
        if (knownIdsRef.current === null) {
          knownIdsRef.current = new Set(nextItems.map(i => i.id));
        } else {
          const newUnread = nextItems.filter(i => !i.read && !knownIdsRef.current.has(i.id));
          nextItems.forEach(i => knownIdsRef.current.add(i.id));
          if (newUnread.length > 0) {
            playNotificationSound(false);
            if (!result.push_subscribed) {
              sendDesktopNotification(newUnread[0]);
            }
          }
        }
        setItems(nextItems);
        setError('');
      }
    } catch (err) { if (generation.current === run) setError(err.message); }
  }, []);

  React.useEffect(() => {
    generation.current += 1;
    knownIdsRef.current = null;
    setItems(mergeWithLocalSceneNotifications([])); setError('');
    if (!ready) return;
    let active = true;
    let checking = false;
    async function check() {
      if (!active || checking || document.hidden) return;
      checking = true;
      try {
        const lexicon = buildLiveLexicon(current.current.db || {});
        const lexiconById = new Map(lexicon.map(e => [e.id, e]));
        let deck = {}; try { deck = JSON.parse(localStorage.getItem('seamenese_srs_v2') || '{}'); } catch {}
        const allowedIds = lexiconById.size > 0 ? new Set(lexiconById.keys()) : null;
        const due = SeameneseCommunityModel.dueSrsCards(deck, Date.now(), allowedIds);
        if (due.length) {
          const cards = due
            .filter(card => !lexiconById.size || lexiconById.has(card.id))
            .slice(0, 200)
            .map(card => {
              const entry = lexiconById.get(card.id);
              return {
                ...card,
                pos: entry?.pos || (SeameneseCommunityModel.inferSrsWordType ? SeameneseCommunityModel.inferSrsWordType(card.id) : 'noun'),
              };
            });
          if (cards.length) {
            await communityRequest('/api/notifications/srs', { method: 'POST', body: JSON.stringify({ cards }) });
          }
        }
        if (active) await refresh();
      } catch (err) { if (active) setError(err.message); }
      finally { checking = false; }
    }
    check();
    const timer = setInterval(check, 15_000);
    const update = () => { if (active) refresh(); };
    window.addEventListener('seamenese-notifications-updated', update);
    window.addEventListener('focus', check);
    document.addEventListener('visibilitychange', check);
    return () => { active = false; clearInterval(timer); window.removeEventListener('seamenese-notifications-updated', update); window.removeEventListener('focus', check); document.removeEventListener('visibilitychange', check); };
  }, [ready, account?.id, profileId, refresh]);

  async function markRead(ids) {
    if (!ids.length) return;
    if (typeof window !== 'undefined' && window.loadLocalSceneNotifications && window.saveLocalSceneNotifications) {
      const localList = window.loadLocalSceneNotifications();
      if (localList.some(item => ids.includes(item.id))) {
        window.saveLocalSceneNotifications(
          localList.map(item => ids.includes(item.id) ? { ...item, read: true } : item)
        );
      }
    }
    setItems(previous => previous.map(item => ids.includes(item.id) ? { ...item, read: true } : item));
    const serverIds = ids.filter(id => !String(id).startsWith('local-scene-gen-'));
    if (!serverIds.length) return;
    try {
      await communityRequest('/api/notifications/read', { method: 'POST', body: JSON.stringify({ ids: serverIds }) });
    } catch (err) { setError(err.message); }
  }

  async function deleteRead(ids = [], all = false) {
    if (!all && (!Array.isArray(ids) || !ids.length)) return;
    if (typeof window !== 'undefined' && window.loadLocalSceneNotifications && window.saveLocalSceneNotifications) {
      const localList = window.loadLocalSceneNotifications();
      window.saveLocalSceneNotifications(
        localList.filter(item => {
          if (!item.read) return true;
          if (all) return false;
          return !ids.includes(item.id);
        })
      );
    }
    setItems(previous => previous.filter(item => {
      if (!item.read) return true;
      if (all) return false;
      return !ids.includes(item.id);
    }));
    const serverIds = Array.isArray(ids) ? ids.filter(id => !String(id).startsWith('local-scene-gen-')) : [];
    if (!all && !serverIds.length) return;
    try {
      await communityRequest('/api/notifications/delete', {
        method: 'POST',
        body: JSON.stringify(all ? { all: true } : { ids: serverIds }),
      });
    } catch (err) { setError(err.message); }
  }

  return {
    items,
    pushSubscribed,
    error,
    refresh,
    markRead,
    deleteRead,
    unread: items.filter(item => !item.read).length,
    readCount: items.filter(item => item.read).length,
  };
}

function NotificationMenu({ source, onSelect, onOpenSettings }) {
  const [open, setOpen] = React.useState(false);
  const [srsOpen, setSrsOpen] = React.useState(false);
  const [sceneGen, setSceneGen] = React.useState(() =>
    typeof window !== 'undefined' && window.SeameneseSceneGenManager
      ? window.SeameneseSceneGenManager.getState()
      : { active: false }
  );
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (typeof window === 'undefined' || !window.SeameneseSceneGenManager) return;
    setSceneGen(window.SeameneseSceneGenManager.getState());
    return window.SeameneseSceneGenManager.subscribe(setSceneGen);
  }, []);

  React.useEffect(() => {
    if (!open) return;
    const close = event => { if (!ref.current?.contains(event.target)) setOpen(false); };
    const escape = event => { if (event.key === 'Escape') setOpen(false); };
    document.addEventListener('pointerdown', close); window.addEventListener('keydown', escape);
    return () => { document.removeEventListener('pointerdown', close); window.removeEventListener('keydown', escape); };
  }, [open]);

  const srsItems = source.items.filter(item => item.kind === 'srs');
  const unreadSrs = srsItems.filter(item => !item.read);
  const readSrs = srsItems.filter(item => item.read);
  const readAll = source.items.filter(item => item.read);
  const hasActiveSceneGen = Boolean(sceneGen && sceneGen.active);
  const sceneGenPct = Math.max(4, Math.min(100, Number(sceneGen?.percent) || 5));
  const badgeCount = source.unread + (hasActiveSceneGen && sceneGen.dismissedToDropdown ? 1 : 0);

  // Build display entries so all SRS notifications stack into a single embedded dropdown at the position of the latest SRS item
  const displayEntries = [];
  let srsInserted = false;
  for (const item of source.items) {
    if (item.kind === 'srs') {
      if (!srsInserted) {
        displayEntries.push({ type: 'srs-stack', items: srsItems });
        srsInserted = true;
      }
    } else {
      displayEntries.push({ type: 'single', item });
    }
  }

  function renderSingleNotification(item, isEmbeddedSrs = false) {
    const cleanBody = item.kind === 'srs' && SeameneseCommunityModel.formatSrsNotificationBody && !/^It is time to review an? [a-z]+\.$/i.test(String(item.body || ''))
      ? SeameneseCommunityModel.formatSrsNotificationBody(item.reference || item.body)
      : item.body;
    return (
      <div key={item.id} className={`notification-item-wrap ${!item.read ? 'is-unread' : 'is-read'} ${isEmbeddedSrs ? 'is-embedded-srs' : ''}`}>
        <button
          className={`notification-item ${!item.read ? 'is-unread' : ''}`}
          type="button"
          onClick={() => {
            if (!item.read) source.markRead([item.id]);
            setOpen(false);
            onSelect(item);
          }}
        >
          <strong>{item.title}</strong>
          <span>{cleanBody}</span>
          <time dateTime={item.created_at}>{relTime(item.created_at)}</time>
        </button>
        {item.read && (
          <button
            type="button"
            className="notification-delete-btn"
            aria-label="Delete read notification"
            title="Delete read notification"
            onClick={(e) => {
              e.stopPropagation();
              source.deleteRead([item.id], false);
            }}
          >
            ✕
          </button>
        )}
      </div>
    );
  }

  return <div className="notification-menu" ref={ref}>
    <button type="button" className="btn notification-trigger" aria-label={`Notifications${badgeCount ? `, ${badgeCount} unread` : ''}`} aria-expanded={open} onClick={() => { setOpen(!open); if (!open) source.refresh(); }}><span className="notification-bell" aria-hidden="true">🔔</span>{badgeCount > 0 && <span className="notification-count">{badgeCount > 99 ? '99+' : badgeCount}</span>}</button>
    {open && <section className="notification-dropdown" aria-label="Recent notifications">
      <div className="community-heading">
        <h3 className="serif">Notifications</h3>
        <div className="notification-head-actions">
          <button className="btn" type="button" disabled={!source.unread} onClick={() => source.markRead(source.items.filter(n => !n.read).map(n => n.id))}>Mark all read</button>
          <button className="btn notification-delete-all-btn" type="button" disabled={!readAll.length} onClick={() => source.deleteRead([], true)} title="Delete all notifications that have been read">Delete all</button>
        </div>
      </div>
      {source.error && <p className="community-error" role="alert">{source.error}</p>}
      {hasActiveSceneGen && (
        <div
          className="notification-scene-gen-card"
          role="status"
          aria-live="polite"
          onClick={() => {
            setOpen(false);
            onSelect({ target: 'scenes' });
          }}
          style={{ cursor: 'pointer' }}
          title="Click to open Dojo → Scenes"
        >
          <div className="notification-scene-gen-head">
            <div className="notification-scene-gen-title">
              ⏳ Generating +10 {sceneGen.tier ? `Tier ${sceneGen.tier} ` : ''}Scenes
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <span className="notification-scene-gen-pct">{sceneGenPct}%</span>
              {sceneGen.dismissedToDropdown && (
                <button
                  type="button"
                  className="btn"
                  style={{ padding: '1px 6px', fontSize: 10 }}
                  title="Restore progress bar to lower-right corner"
                  onClick={(e) => {
                    e.stopPropagation();
                    window.SeameneseSceneGenManager?.restoreFromDropdown();
                  }}
                >
                  Pop out
                </button>
              )}
            </div>
          </div>
          <div className="notification-scene-gen-stage">
            {sceneGen.stageLabel || 'Generating Seamenese dialogues…'}
          </div>
          {sceneGen.detail && (
            <div className="notification-scene-gen-detail">
              {sceneGen.detail}
            </div>
          )}
          <div className="notification-progress-track" aria-hidden="true">
            <div
              className="notification-progress-fill"
              style={{ width: `${sceneGenPct}%` }}
            />
          </div>
        </div>
      )}
      {!source.items.length && !hasActiveSceneGen && <p className="community-muted">No notifications yet. Mentions, scheduled SRS reviews and leaderboard changes will appear here.</p>}
      <div className="notification-list">
        {displayEntries.map(entry => {
          if (entry.type === 'single') {
            return renderSingleNotification(entry.item, false);
          }
          const latestSrs = srsItems[0];
          return (
            <div key="srs-stack" className={`notification-srs-stack ${unreadSrs.length > 0 ? 'has-unread' : ''}`}>
              <div className="notification-srs-stack-head">
                <button
                  type="button"
                  className="notification-srs-toggle"
                  aria-expanded={srsOpen}
                  onClick={() => setSrsOpen(prev => !prev)}
                >
                  <div className="notification-srs-toggle-top">
                    <strong>
                      📚 SRS Reviews ({srsItems.length})
                      {unreadSrs.length > 0 && <span className="notification-srs-badge">{unreadSrs.length} unread</span>}
                    </strong>
                    <span className="notification-srs-chevron" aria-hidden="true">{srsOpen ? '▾' : '▸'}</span>
                  </div>
                  <span className="notification-srs-summary">
                    {srsItems.length === 1
                      ? (SeameneseCommunityModel.formatSrsNotificationBody
                          ? SeameneseCommunityModel.formatSrsNotificationBody(latestSrs.reference || latestSrs.body)
                          : latestSrs.body)
                      : `${srsItems.length} scheduled SRS review notifications · click to ${srsOpen ? 'hide' : 'expand'}`}
                  </span>
                  {latestSrs && <time dateTime={latestSrs.created_at}>{relTime(latestSrs.created_at)}</time>}
                </button>
                <div className="notification-srs-stack-actions">
                  <button
                    type="button"
                    className="btn notification-srs-go-btn"
                    onClick={() => {
                      if (unreadSrs.length) source.markRead(unreadSrs.map(n => n.id));
                      setOpen(false);
                      onSelect(latestSrs || { target: 'srs' });
                    }}
                  >
                    Review
                  </button>
                  {readSrs.length > 0 && (
                    <button
                      type="button"
                      className="notification-delete-btn"
                      title={`Delete ${readSrs.length} read SRS notification${readSrs.length === 1 ? '' : 's'}`}
                      aria-label="Delete read SRS notifications"
                      onClick={() => source.deleteRead(readSrs.map(n => n.id), false)}
                    >
                      ✕
                    </button>
                  )}
                </div>
              </div>
              {srsOpen && (
                <div className="notification-srs-embedded-list">
                  {srsItems.map(item => renderSingleNotification(item, true))}
                </div>
              )}
            </div>
          );
        })}
      </div>
      {onOpenSettings && (
        <div style={{ marginTop: 10, paddingTop: 8, borderTop: '1px solid var(--rule, rgba(255,255,255,0.1))', textAlign: 'center' }}>
          <button
            type="button"
            onClick={() => {
              setOpen(false);
              onOpenSettings();
            }}
            style={{
              background: 'none',
              border: 'none',
              padding: '2px 4px',
              fontSize: 11,
              color: 'var(--fg-mute, #9ca3af)',
              textDecoration: 'underline',
              textUnderlineOffset: 3,
              cursor: 'pointer',
            }}
          >
            Enable push notifications in settings
          </button>
        </div>
      )}
    </section>}
  </div>;
}
