import { useEffect, useRef, useCallback, useState } from 'react';
import { initializeApp, FirebaseApp } from 'firebase/app';
import { getMessaging, getToken, onMessage, Messaging } from 'firebase/messaging';
import axios from 'axios';

export interface FirebaseMessage {
  type: string;
  title?: string;
  body?: string;
  [key: string]: unknown;
}

interface UseFirebaseMessagingOptions {
  onForegroundMessage?: (message: FirebaseMessage) => void;
  onNotificationClick?: (data: FirebaseMessage) => void;
  enabled?: boolean;
}

interface UseFirebaseMessagingReturn {
  supported: boolean;
  permissionGranted: boolean;
  token: string | null;
  error: string | null;
}

/**
 * Hook to initialize Firebase Cloud Messaging for browser push notifications.
 *
 * Flow:
 * 1. Fetch Firebase web config from /zeiterfassung/firebase-config
 * 2. Initialize Firebase app + register service worker
 * 3. Request notification permission
 * 4. Get FCM token and register it with the backend
 * 5. Listen for foreground messages → call onForegroundMessage
 * 6. Listen for service worker notification clicks → call onNotificationClick
 */
export default function useFirebaseMessaging({
  onForegroundMessage,
  onNotificationClick,
  enabled = true,
}: UseFirebaseMessagingOptions): UseFirebaseMessagingReturn {
  const [supported, setSupported] = useState<boolean>(true);
  const [permissionGranted, setPermissionGranted] = useState<boolean>(false);
  const [token, setToken] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  const appRef = useRef<FirebaseApp | null>(null);
  const messagingRef = useRef<Messaging | null>(null);
  const initRef = useRef<boolean>(false);

  // Stable callback refs
  const onForegroundRef = useRef(onForegroundMessage);
  onForegroundRef.current = onForegroundMessage;
  const onClickRef = useRef(onNotificationClick);
  onClickRef.current = onNotificationClick;

  const init = useCallback(async () => {
    if (initRef.current) return;
    initRef.current = true;

    // Check browser support
    if (!('serviceWorker' in navigator) || !('Notification' in window)) {
      setSupported(false);
      return;
    }

    try {
      // 1. Fetch Firebase web config from backend
      const configRes = await axios.get('/zeiterfassung/firebase-config');
      const firebaseConfig = configRes.data;

      if (!firebaseConfig.apiKey) {
        setError('Firebase config not available');
        return;
      }

      // 2. Initialize Firebase
      appRef.current = initializeApp(firebaseConfig);

      // 3. Register service worker and wait for it to be ready + controlling
      const swRegistration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');

      // Wait for the SW to be active
      if (swRegistration.installing || swRegistration.waiting) {
        const sw = swRegistration.installing || swRegistration.waiting;
        await new Promise<void>((resolve) => {
          sw!.addEventListener('statechange', (e) => {
            if ((e.target as ServiceWorker).state === 'activated') {
              resolve();
            }
          });
        });
      }

      // Wait for the SW to claim this page (controller becomes non-null)
      if (!navigator.serviceWorker.controller) {
        await new Promise<void>((resolve) => {
          navigator.serviceWorker.addEventListener('controllerchange', () => resolve(), { once: true });
        });
      }

      swRegistration.active?.postMessage({
        type: 'FIREBASE_CONFIG',
        config: firebaseConfig,
      });

      // 4. Get messaging instance
      messagingRef.current = getMessaging(appRef.current);

      // 5. Request notification permission
      const permission = await Notification.requestPermission();
      if (permission !== 'granted') {
        setPermissionGranted(false);
        return;
      }
      setPermissionGranted(true);

      // 6. Get FCM token
      const fcmToken = await getToken(messagingRef.current, {
        vapidKey: firebaseConfig.vapidKey,
        serviceWorkerRegistration: swRegistration,
      });

      if (fcmToken) {
        setToken(fcmToken);

        // Register token with backend
        await axios.post('/zeiterfassung/browser-push-token', {
          token: fcmToken,
        });
      }

      // 7. Listen for foreground messages
      onMessage(messagingRef.current, (payload) => {
        const data: FirebaseMessage = {
          type: (payload.data?.type as string) || 'general',
          title: payload.notification?.title || (payload.data?.title as string),
          body: payload.notification?.body || (payload.data?.body as string),
          ...payload.data,
        };
        onForegroundRef.current?.(data);
      });

    } catch (err: unknown) {
      const message = err instanceof Error ? err.message : 'Firebase init failed';
      setError(message);
    }
  }, []);

  // Initialize on mount
  useEffect(() => {
    if (enabled) {
      init();
    }
  }, [enabled, init]);

  // Listen for service worker notification click messages
  useEffect(() => {
    if (!enabled) return;

    const handler = (event: MessageEvent) => {
      if (event.data?.type === 'NOTIFICATION_CLICK') {
        onClickRef.current?.(event.data.data);
      }
    };

    navigator.serviceWorker?.addEventListener('message', handler);
    return () => {
      navigator.serviceWorker?.removeEventListener('message', handler);
    };
  }, [enabled]);

  // Cleanup token on page unload (best-effort)
  useEffect(() => {
    if (!token) return;

    const cleanup = () => {
      // Use sendBeacon for reliable delivery during unload
      const data = JSON.stringify({ token });
      navigator.sendBeacon?.(
        '/zeiterfassung/browser-push-token?_method=DELETE',
        new Blob([data], { type: 'application/json' })
      );
    };

    // Note: we do NOT remove on page unload — token persists across refreshes.
    // Token is removed on explicit logout only (via removeToken call).

    return () => {
      // React cleanup — component unmount doesn't mean logout
    };
  }, [token]);

  return { supported, permissionGranted, token, error };
}
