// Push Notifications Utility for ParentFlow Web App
// Handles Web Push subscription and management

const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://maternal-api.noru1.ro';

export interface PushSubscriptionData {
  endpoint: string;
  keys: {
    p256dh: string;
    auth: string;
  };
}

/**
 * Convert VAPID public key from base64 to Uint8Array
 */
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;
}

/**
 * Check if push notifications are supported
 */
export function isPushNotificationSupported(): boolean {
  if (typeof window === 'undefined') return false;
  return 'serviceWorker' in navigator && 'PushManager' in window && 'Notification' in window;
}

/**
 * Get current notification permission status
 */
export function getNotificationPermission(): NotificationPermission {
  if (typeof window === 'undefined' || !('Notification' in window)) {
    return 'default';
  }
  return Notification.permission;
}

/**
 * Request notification permission
 */
export async function requestNotificationPermission(): Promise<NotificationPermission> {
  if (!isPushNotificationSupported()) {
    throw new Error('Push notifications are not supported in this browser');
  }

  const permission = await Notification.requestPermission();
  console.log('[Push] Permission result:', permission);
  return permission;
}

/**
 * Get or fetch the VAPID public key
 */
export async function getVapidPublicKey(token?: string): Promise<string> {
  try {
    const headers: HeadersInit = {
      'Content-Type': 'application/json',
    };

    if (token) {
      headers['Authorization'] = `Bearer ${token}`;
    }

    const response = await fetch(`${API_BASE_URL}/api/v1/push/vapid-public-key`, {
      method: 'GET',
      headers,
    });

    if (!response.ok) {
      throw new Error(`Failed to get VAPID key: ${response.statusText}`);
    }

    const data = await response.json();
    return data.publicKey;
  } catch (error) {
    console.error('[Push] Error getting VAPID key:', error);
    throw error;
  }
}

/**
 * Register service worker for push notifications
 */
export async function registerPushServiceWorker(): Promise<ServiceWorkerRegistration> {
  if (!('serviceWorker' in navigator)) {
    throw new Error('Service Worker not supported');
  }

  try {
    // Check if already registered
    const existingRegistration = await navigator.serviceWorker.getRegistration('/push-sw.js');
    if (existingRegistration) {
      console.log('[Push] Service Worker already registered');
      return existingRegistration;
    }

    // Register new service worker
    const registration = await navigator.serviceWorker.register('/push-sw.js', {
      scope: '/',
    });

    console.log('[Push] Service Worker registered:', registration.scope);

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

    return registration;
  } catch (error) {
    console.error('[Push] Service Worker registration failed:', error);
    throw error;
  }
}

/**
 * Subscribe to push notifications
 */
export async function subscribeToPush(token: string): Promise<PushSubscription> {
  if (!isPushNotificationSupported()) {
    throw new Error('Push notifications are not supported');
  }

  // Request permission first
  const permission = await requestNotificationPermission();
  if (permission !== 'granted') {
    throw new Error('Notification permission denied');
  }

  try {
    // Register service worker
    const registration = await registerPushServiceWorker();

    // Get VAPID public key
    const vapidPublicKey = await getVapidPublicKey(token);
    const applicationServerKey = urlBase64ToUint8Array(vapidPublicKey);

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

    console.log('[Push] Subscribed to push notifications');

    // Send subscription to backend
    await savePushSubscription(subscription, token);

    return subscription;
  } catch (error) {
    console.error('[Push] Error subscribing to push:', error);
    throw error;
  }
}

/**
 * Save push subscription to backend
 */
export async function savePushSubscription(
  subscription: PushSubscription,
  token: string
): Promise<void> {
  try {
    const subscriptionData = subscription.toJSON();

    const response = await fetch(`${API_BASE_URL}/api/v1/push/subscriptions`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
      body: JSON.stringify(subscriptionData),
    });

    if (!response.ok) {
      throw new Error(`Failed to save subscription: ${response.statusText}`);
    }

    console.log('[Push] Subscription saved to backend');
  } catch (error) {
    console.error('[Push] Error saving subscription:', error);
    throw error;
  }
}

/**
 * Get current push subscription
 */
export async function getPushSubscription(): Promise<PushSubscription | null> {
  if (!isPushNotificationSupported()) {
    return null;
  }

  try {
    const registration = await navigator.serviceWorker.getRegistration('/push-sw.js');
    if (!registration) {
      return null;
    }

    const subscription = await registration.pushManager.getSubscription();
    return subscription;
  } catch (error) {
    console.error('[Push] Error getting subscription:', error);
    return null;
  }
}

/**
 * Unsubscribe from push notifications
 */
export async function unsubscribeFromPush(token: string): Promise<void> {
  try {
    const subscription = await getPushSubscription();
    if (!subscription) {
      console.log('[Push] No active subscription to unsubscribe');
      return;
    }

    const endpoint = subscription.endpoint;

    // Unsubscribe locally
    await subscription.unsubscribe();
    console.log('[Push] Unsubscribed locally');

    // Remove from backend
    await fetch(`${API_BASE_URL}/api/v1/push/subscriptions?endpoint=${encodeURIComponent(endpoint)}`, {
      method: 'DELETE',
      headers: {
        Authorization: `Bearer ${token}`,
      },
    });

    console.log('[Push] Subscription removed from backend');
  } catch (error) {
    console.error('[Push] Error unsubscribing:', error);
    throw error;
  }
}

/**
 * Check if user is subscribed to push notifications
 */
export async function isPushSubscribed(): Promise<boolean> {
  const subscription = await getPushSubscription();
  return subscription !== null;
}

/**
 * Send a test push notification
 */
export async function sendTestPushNotification(token: string): Promise<void> {
  try {
    const response = await fetch(`${API_BASE_URL}/api/v1/push/test`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (!response.ok) {
      throw new Error(`Failed to send test notification: ${response.statusText}`);
    }

    console.log('[Push] Test notification sent');
  } catch (error) {
    console.error('[Push] Error sending test notification:', error);
    throw error;
  }
}

/**
 * Get push notification statistics
 */
export async function getPushStatistics(token: string): Promise<any> {
  try {
    const response = await fetch(`${API_BASE_URL}/api/v1/push/statistics`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
    });

    if (!response.ok) {
      throw new Error(`Failed to get statistics: ${response.statusText}`);
    }

    return await response.json();
  } catch (error) {
    console.error('[Push] Error getting statistics:', error);
    throw error;
  }
}

/**
 * Show a local test notification (no server needed)
 */
export async function showLocalTestNotification(): Promise<void> {
  if (getNotificationPermission() !== 'granted') {
    await requestNotificationPermission();
  }

  if (getNotificationPermission() === 'granted') {
    const registration = await navigator.serviceWorker.getRegistration('/push-sw.js');
    if (registration) {
      await registration.showNotification('ParentFlow Test', {
        body: 'This is a local test notification',
        icon: '/icons/icon-192x192.png',
        badge: '/icons/icon-72x72.png',
        tag: 'test',
        data: { url: '/' },
      });
    }
  }
}
