// Web Push singleton — window.Push
// Handles subscription lifecycle: subscribe, unsubscribe, re-register on load.
const Push = (() => {
  function urlBase64ToUint8Array(b64) {
    const padding = '='.repeat((4 - (b64.length % 4)) % 4);
    const base64 = (b64 + padding).replace(/-/g, '+').replace(/_/g, '/');
    return Uint8Array.from([...atob(base64)].map(c => c.charCodeAt(0)));
  }

  function uint8ArrayToBase64Url(bytes) {
    let str = '';
    bytes.forEach(b => { str += String.fromCharCode(b); });
    return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
  }

  function keysMatch(existingKey, vapidKey) {
    if (!existingKey || !vapidKey) return false;
    try {
      const bytes = existingKey instanceof Uint8Array ? existingKey : new Uint8Array(existingKey);
      return uint8ArrayToBase64Url(bytes) === vapidKey;
    } catch {
      return false;
    }
  }

  async function getVapidKey() {
    const { key } = await API.get('/api/push/vapid-public-key');
    return key;
  }

  async function ensureCurrentSubscription({ forceRenew = false } = {}) {
    const reg = await navigator.serviceWorker.ready;
    const vapidKey = await getVapidKey();
    const nextKey = urlBase64ToUint8Array(vapidKey);
    let sub = await reg.pushManager.getSubscription();

    if (sub) {
      const currentKey = sub.options && sub.options.applicationServerKey;
      if (forceRenew || !keysMatch(currentKey, vapidKey)) {
        await API.post('/api/push/unsubscribe', { endpoint: sub.endpoint }).catch(() => {});
        await sub.unsubscribe().catch(() => {});
        sub = null;
      }
    }

    if (!sub) {
      sub = await reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: nextKey,
      });
    }

    await API.post('/api/push/subscribe', sub.toJSON());
    return sub;
  }

  async function subscribe() {
    if (!('serviceWorker' in navigator) || !('PushManager' in window))
      throw new Error('Push notifications are not supported in this browser.');

    const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
    const isStandalone = window.matchMedia('(display-mode: standalone)').matches
      || window.navigator.standalone === true;
    if (isIOS && !isStandalone)
      throw new Error('On iPhone: open Safari → Share → "Add to Home Screen", then open the app from your home screen and try again.');

    const perm = await Notification.requestPermission();
    if (perm !== 'granted')
      throw new Error('Notification permission was denied. Enable it in iPhone Settings → Velonics Hub → Notifications.');

    const sub = await ensureCurrentSubscription({ forceRenew: true });
    console.log('[Push] Subscribed');
    return sub;
  }

  async function unsubscribe() {
    if (!('serviceWorker' in navigator)) return;
    const reg = await navigator.serviceWorker.ready;
    const sub = await reg.pushManager.getSubscription();
    if (!sub) return;
    await API.post('/api/push/unsubscribe', { endpoint: sub.endpoint }).catch(() => {});
    await sub.unsubscribe();
    console.log('[Push] Unsubscribed');
  }

  async function setup() {
    if (!('serviceWorker' in navigator) || !('PushManager' in window)) return;
    if (Notification.permission !== 'granted') return;
    try {
      await ensureCurrentSubscription();
    } catch (err) {
      console.warn('[Push] Setup skipped:', err.message);
    }
  }

  return { subscribe, unsubscribe, setup };
})();

window.Push = Push;
