import { useCallback, useEffect, useState } from "react";
import { pushApi } from "../api/push";

/**
 * Converts a base64url-encoded VAPID public key to a Uint8Array
 * as required by pushManager.subscribe({ applicationServerKey }).
 */
function urlBase64ToUint8Array(base64String: string): Uint8Array {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
  const rawData = atob(base64);
  const outputArray = new Uint8Array(rawData.length);
  for (let i = 0; i < rawData.length; ++i) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

const isSupported =
  typeof navigator !== "undefined" &&
  "serviceWorker" in navigator &&
  "PushManager" in window &&
  "Notification" in window;

export function usePushNotifications(): {
  isSupported: boolean;
  permission: NotificationPermission | "unsupported";
  subscribe: () => Promise<void>;
  unsubscribe: () => Promise<void>;
} {
  const [permission, setPermission] = useState<NotificationPermission | "unsupported">(
    isSupported ? Notification.permission : "unsupported",
  );

  // Poll for permission changes (e.g., user revokes permission in browser settings)
  useEffect(() => {
    if (!isSupported) return;
    const interval = setInterval(() => {
      const current = Notification.permission;
      setPermission((prev) => (prev !== current ? current : prev));
    }, 2000);
    return () => clearInterval(interval);
  }, []);

  const subscribe = useCallback(async () => {
    if (!isSupported) return;

    const perm = await Notification.requestPermission();
    setPermission(perm);
    if (perm !== "granted") return;

    const { publicKey } = await pushApi.getVapidPublicKey();
    if (!publicKey) return;

    const reg = await navigator.serviceWorker.ready;
    const sub = await reg.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey: urlBase64ToUint8Array(publicKey).buffer as ArrayBuffer,
    });

    await pushApi.subscribe(sub.toJSON() as ReturnType<PushSubscription["toJSON"]>);
  }, []);

  const unsubscribe = useCallback(async () => {
    if (!isSupported) return;

    const reg = await navigator.serviceWorker.ready;
    const sub = await reg.pushManager.getSubscription();
    if (!sub) return;

    await sub.unsubscribe();
    await pushApi.unsubscribe(sub.endpoint);
  }, []);

  return { isSupported, permission, subscribe, unsubscribe };
}
