// Abonnement Web Push côté navigateur (P4-C). Enregistre le service worker, demande la permission,
// s'abonne avec la clé VAPID publique du serveur, et transmet l'abonnement au daemon.
import { api } from './api';
import type { VapidKeyResponse } from '@arboretum/shared';

const SW_URL = '/sw.js';

/** Push nécessite service worker + PushManager + Notification (et un contexte sécurisé : localhost ou HTTPS). */
export function pushSupported(): boolean {
  return 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window;
}

export function notificationPermission(): NotificationPermission {
  return 'Notification' in window ? Notification.permission : 'denied';
}

export async function registerServiceWorker(): Promise<ServiceWorkerRegistration | null> {
  if (!('serviceWorker' in navigator)) return null;
  try {
    return await navigator.serviceWorker.register(SW_URL);
  } catch {
    return null;
  }
}

// La clé VAPID publique est transmise en base64url ; PushManager attend un BufferSource
// adossé à un ArrayBuffer (pas SharedArrayBuffer) → on type explicitement le buffer.
function urlBase64ToUint8Array(base64: string): Uint8Array<ArrayBuffer> {
  const padding = '='.repeat((4 - (base64.length % 4)) % 4);
  const b64 = (base64 + padding).replace(/-/g, '+').replace(/_/g, '/');
  const raw = atob(b64);
  const out = new Uint8Array(new ArrayBuffer(raw.length));
  for (let i = 0; i < raw.length; i++) out[i] = raw.charCodeAt(i);
  return out;
}

export async function currentSubscription(): Promise<PushSubscription | null> {
  if (!pushSupported()) return null;
  const reg = await navigator.serviceWorker.ready;
  return reg.pushManager.getSubscription();
}

export type EnableResult = 'enabled' | 'denied' | 'unsupported';

export async function enablePush(): Promise<EnableResult> {
  if (!pushSupported()) return 'unsupported';
  const permission = await Notification.requestPermission();
  if (permission !== 'granted') return 'denied';
  await registerServiceWorker();
  const reg = await navigator.serviceWorker.ready;
  const { key } = await api.get<VapidKeyResponse>('/api/v1/push/vapid-public-key');
  const sub =
    (await reg.pushManager.getSubscription()) ??
    (await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(key) }));
  const json = sub.toJSON();
  const keys = json.keys ?? {};
  await api.post('/api/v1/push/subscribe', { endpoint: sub.endpoint, keys: { p256dh: keys.p256dh ?? '', auth: keys.auth ?? '' } });
  return 'enabled';
}

export async function disablePush(): Promise<void> {
  const sub = await currentSubscription();
  if (!sub) return;
  try {
    await api.post('/api/v1/push/unsubscribe', { endpoint: sub.endpoint });
  } catch {
    // le retrait local prime ; un échec réseau sur l'unsubscribe serveur n'est pas bloquant
  }
  await sub.unsubscribe();
}
