'use client';

import { useState, useEffect, useCallback } from 'react';

interface PushSubscriptionState {
  isSupported: boolean;
  isSubscribed: boolean;
  isLoading: boolean;
  permission: NotificationPermission | 'default';
  error: string | null;
}

interface UsePushNotificationsOptions {
  /** Room slug to associate subscription with */
  roomSlug?: string;
  /** Sync server URL for storing subscriptions */
  syncUrl?: string;
}

// VAPID public key - should match the server's public key
// Generate with: npx web-push generate-vapid-keys
const VAPID_PUBLIC_KEY = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY || '';

function urlBase64ToUint8Array(base64String: string): Uint8Array {
  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 function usePushNotifications(options: UsePushNotificationsOptions = {}) {
  const { roomSlug, syncUrl } = options;

  const [state, setState] = useState<PushSubscriptionState>({
    isSupported: false,
    isSubscribed: false,
    isLoading: true,
    permission: 'default',
    error: null,
  });

  const [subscription, setSubscription] = useState<PushSubscription | null>(null);

  // Check if push notifications are supported
  useEffect(() => {
    const checkSupport = async () => {
      const isSupported =
        'serviceWorker' in navigator &&
        'PushManager' in window &&
        'Notification' in window;

      if (!isSupported) {
        setState((prev) => ({
          ...prev,
          isSupported: false,
          isLoading: false,
          error: 'Push notifications are not supported in this browser',
        }));
        return;
      }

      // Check current permission
      const permission = Notification.permission;

      setState((prev) => ({
        ...prev,
        isSupported: true,
        permission,
        isLoading: true,
      }));

      // Register service worker and check subscription
      try {
        const registration = await navigator.serviceWorker.register('/sw.js', {
          scope: '/',
        });

        console.log('Service worker registered:', registration);

        // Wait for the service worker to be ready
        await navigator.serviceWorker.ready;

        // Check existing subscription
        const existingSubscription = await registration.pushManager.getSubscription();

        if (existingSubscription) {
          setSubscription(existingSubscription);
          setState((prev) => ({
            ...prev,
            isSubscribed: true,
            isLoading: false,
          }));
        } else {
          setState((prev) => ({
            ...prev,
            isSubscribed: false,
            isLoading: false,
          }));
        }
      } catch (error) {
        console.error('Service worker registration failed:', error);
        setState((prev) => ({
          ...prev,
          isLoading: false,
          error: 'Failed to register service worker',
        }));
      }
    };

    checkSupport();
  }, []);

  // Subscribe to push notifications
  const subscribe = useCallback(async () => {
    if (!state.isSupported) {
      throw new Error('Push notifications not supported');
    }

    setState((prev) => ({ ...prev, isLoading: true, error: null }));

    try {
      // Request notification permission
      const permission = await Notification.requestPermission();
      setState((prev) => ({ ...prev, permission }));

      if (permission !== 'granted') {
        throw new Error('Notification permission denied');
      }

      // Get service worker registration
      const registration = await navigator.serviceWorker.ready;

      // Check if VAPID key is configured
      if (!VAPID_PUBLIC_KEY) {
        throw new Error('VAPID public key not configured');
      }

      // Subscribe to push notifications
      const applicationServerKey = urlBase64ToUint8Array(VAPID_PUBLIC_KEY);
      const pushSubscription = await registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: applicationServerKey.buffer as ArrayBuffer,
      });

      console.log('Push subscription created:', pushSubscription);

      // Send subscription to server
      if (syncUrl) {
        const response = await fetch(`${syncUrl.replace('wss://', 'https://').replace('ws://', 'http://')}/push/subscribe`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            subscription: pushSubscription.toJSON(),
            roomSlug,
          }),
        });

        if (!response.ok) {
          console.warn('Failed to save subscription to server');
        }
      }

      // Also save to localStorage for persistence
      localStorage.setItem('rmaps_push_subscription', JSON.stringify(pushSubscription.toJSON()));
      if (roomSlug) {
        localStorage.setItem(`rmaps_push_room_${roomSlug}`, 'true');
      }

      setSubscription(pushSubscription);
      setState((prev) => ({
        ...prev,
        isSubscribed: true,
        isLoading: false,
      }));

      return pushSubscription;
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to subscribe';
      console.error('Push subscription failed:', error);
      setState((prev) => ({
        ...prev,
        isLoading: false,
        error: message,
      }));
      throw error;
    }
  }, [state.isSupported, syncUrl, roomSlug]);

  // Unsubscribe from push notifications
  const unsubscribe = useCallback(async () => {
    if (!subscription) {
      return;
    }

    setState((prev) => ({ ...prev, isLoading: true, error: null }));

    try {
      // Unsubscribe from push manager
      await subscription.unsubscribe();

      // Remove from server
      if (syncUrl) {
        try {
          await fetch(`${syncUrl.replace('wss://', 'https://').replace('ws://', 'http://')}/push/unsubscribe`, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              endpoint: subscription.endpoint,
              roomSlug,
            }),
          });
        } catch {
          // Ignore server errors on unsubscribe
        }
      }

      // Remove from localStorage
      localStorage.removeItem('rmaps_push_subscription');
      if (roomSlug) {
        localStorage.removeItem(`rmaps_push_room_${roomSlug}`);
      }

      setSubscription(null);
      setState((prev) => ({
        ...prev,
        isSubscribed: false,
        isLoading: false,
      }));
    } catch (error) {
      const message = error instanceof Error ? error.message : 'Failed to unsubscribe';
      console.error('Push unsubscribe failed:', error);
      setState((prev) => ({
        ...prev,
        isLoading: false,
        error: message,
      }));
      throw error;
    }
  }, [subscription, syncUrl, roomSlug]);

  // Toggle subscription
  const toggleSubscription = useCallback(async () => {
    if (state.isSubscribed) {
      await unsubscribe();
    } else {
      await subscribe();
    }
  }, [state.isSubscribed, subscribe, unsubscribe]);

  return {
    ...state,
    subscription,
    subscribe,
    unsubscribe,
    toggleSubscription,
  };
}
