import { useEffect, useRef, useCallback } from 'react';
import { useAuthStore } from '@/stores/auth.store';
import { useSettingsStore } from '@/stores/settings.store';
import { useSocialStore } from '@/stores/social.store';

/**
 * SSE hook — establishes EventSource connection for real-time social events.
 * Auto-reconnects with exponential backoff. Passes JWT via query param
 * since EventSource doesn't support custom headers.
 */
export function useSSE() {
  const esRef = useRef<EventSource | null>(null);
  const retryRef = useRef<ReturnType<typeof setTimeout>>(undefined);
  const retryCount = useRef(0);
  const maxRetryDelay = 30_000; // 30s max

  const accessToken = useAuthStore((s) => s.accessToken);
  const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
  const enableSocial = useSettingsStore((s) => s.settings?.enableSocial);

  const handleNotification = useCallback((event: MessageEvent) => {
    try {
      const data = JSON.parse(event.data);
      // Increment unread count in store
      useSocialStore.setState((state) => ({
        unreadNotificationCount: state.unreadNotificationCount + 1,
      }));
      // If the notification dropdown was recently opened, prepend to list
      const currentNotifications = useSocialStore.getState().notifications;
      if (currentNotifications.length > 0) {
        useSocialStore.setState((state) => ({
          notifications: [{ ...data, isRead: false }, ...state.notifications].slice(0, 20),
        }));
      }
    } catch {}
  }, []);

  const handlePresence = useCallback((event: MessageEvent) => {
    try {
      const data = JSON.parse(event.data);
      useSocialStore.setState((state) => {
        if (data.isOnline) {
          // Add to online friends (avoid duplicates)
          const exists = state.onlineFriends.some((f) => f.userId === data.userId);
          if (exists) return state;
          return {
            onlineFriends: [...state.onlineFriends, {
              userId: data.userId,
              name: data.name,
              email: data.email,
            }],
          };
        } else {
          // Remove from online friends
          return {
            onlineFriends: state.onlineFriends.filter((f) => f.userId !== data.userId),
          };
        }
      });
    } catch {}
  }, []);

  const handleFriendRequest = useCallback((_event: MessageEvent) => {
    // Refresh pending received when we get a friend request SSE
    useSocialStore.getState().fetchPendingReceived();
  }, []);

  const handleFriendAccepted = useCallback((_event: MessageEvent) => {
    // Refresh friends list when a request is accepted
    useSocialStore.getState().fetchFriends();
  }, []);

  const connect = useCallback(async () => {
    if (!accessToken || !enableSocial) return;

    // Close existing connection if any
    if (esRef.current) {
      esRef.current.close();
      esRef.current = null;
    }

    // Obtain a signed URL instead of embedding the full JWT in the query
    // string (2026-04-12 — see utils/signed-url.ts for rationale).
    let url: string;
    try {
      const signRes = await fetch('/media/api/media/sign', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}` },
        body: JSON.stringify({ path: '/api/social/sse', ttlSeconds: 300 }),
      });
      if (!signRes.ok) throw new Error('sign failed');
      const { url: signedPath } = await signRes.json();
      url = signedPath; // absolute path, nginx routes /api/social to Express
    } catch {
      return; // SSE unavailable; non-critical
    }

    const es = new EventSource(url);
    esRef.current = es;

    es.addEventListener('connected', () => {
      retryCount.current = 0;
    });

    es.addEventListener('notification', handleNotification);
    es.addEventListener('presence', handlePresence);
    es.addEventListener('friend_request', handleFriendRequest);
    es.addEventListener('friend_accepted', handleFriendAccepted);
    es.addEventListener('poke', handleNotification);

    es.onerror = () => {
      es.close();
      esRef.current = null;
      const delay = Math.min(1000 * 2 ** retryCount.current, maxRetryDelay);
      retryCount.current++;
      retryRef.current = setTimeout(() => { void connect(); }, delay);
    };
  }, [accessToken, enableSocial, handleNotification, handlePresence, handleFriendRequest, handleFriendAccepted]);

  useEffect(() => {
    if (!isAuthenticated || !enableSocial) return;

    void connect();

    // Fetch initial online friends list
    useSocialStore.getState().fetchOnlineFriends();

    return () => {
      if (esRef.current) {
        esRef.current.close();
        esRef.current = null;
      }
      if (retryRef.current) {
        clearTimeout(retryRef.current);
      }
    };
  }, [isAuthenticated, enableSocial, connect]);
}
