import { create } from 'zustand';
import { api } from '../lib/api.ts';

interface PushState {
  isSupported: boolean;
  isSubscribed: boolean;
  permission: NotificationPermission;
  subscribe: () => Promise<void>;
  unsubscribe: () => Promise<void>;
  requestPermission: () => Promise<NotificationPermission>;
  checkSubscription: () => Promise<void>;
}

function urlBase64ToUint8Array(base64String: string): BufferSource {
  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) {
    outputArray[i] = rawData.charCodeAt(i);
  }
  return outputArray;
}

export const usePushStore = create<PushState>((set, get) => ({
  isSupported: 'serviceWorker' in navigator && 'PushManager' in window,
  isSubscribed: false,
  permission: typeof Notification !== 'undefined' ? Notification.permission : 'default',

  requestPermission: async () => {
    if (!get().isSupported) return 'denied';
    const permission = await Notification.requestPermission();
    set({ permission });
    return permission;
  },

  checkSubscription: async () => {
    if (!get().isSupported) return;
    try {
      const registration = await navigator.serviceWorker.ready;
      const subscription = await registration.pushManager.getSubscription();
      set({ isSubscribed: !!subscription });
    } catch {
      // ignore
    }
  },

  subscribe: async () => {
    if (!get().isSupported) return;

    try {
      // Request notification permission first
      const permission = await get().requestPermission();
      if (permission !== 'granted') return;

      // Register service worker
      const registration = await navigator.serviceWorker.register('/sw.js');
      await navigator.serviceWorker.ready;

      // Get VAPID public key from server
      const { publicKey } = await api.get<{ publicKey: string }>('/push/vapid-public-key');
      if (!publicKey) return;

      // Subscribe to push
      const subscription = await registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(publicKey),
      });

      const sub = subscription.toJSON();
      const keys = sub.keys as { p256dh: string; auth: string };

      // Send subscription to server
      await api.post('/push/subscribe', {
        endpoint: sub.endpoint!,
        p256dh: keys.p256dh,
        auth: keys.auth,
      });

      set({ isSubscribed: true });
    } catch (error) {
      console.error('Failed to subscribe to push:', error);
    }
  },

  unsubscribe: async () => {
    if (!get().isSupported) return;

    try {
      const registration = await navigator.serviceWorker.ready;
      const subscription = await registration.pushManager.getSubscription();
      if (subscription) {
        await api.post('/push/unsubscribe', { endpoint: subscription.endpoint });
        await subscription.unsubscribe();
      }
      set({ isSubscribed: false });
    } catch (error) {
      console.error('Failed to unsubscribe from push:', error);
    }
  },
}));
