import { useEffect, useRef, useState, useCallback } from 'react';
import { useAuthStore } from '@/stores/authStore';

interface UseSSEOptions {
  enabled?: boolean;
  onMessage?: (event: MessageEvent) => void;
}

async function fetchSSEToken(): Promise<string | null> {
  const token = useAuthStore.getState().token;
  if (!token) return null;
  try {
    const res = await fetch('/api/auth/sse-token', {
      method: 'POST',
      headers: { Authorization: `Bearer ${token}` },
    });
    if (!res.ok) return null;
    const body = await res.json();
    return body.token ?? null;
  } catch {
    return null;
  }
}

export function useSSE<T = unknown>(url: string, options: UseSSEOptions = {}) {
  const { enabled = true, onMessage } = options;
  const [data, setData] = useState<T | null>(null);
  const [connected, setConnected] = useState(false);
  const [error, setError] = useState<Error | null>(null);
  const eventSourceRef = useRef<EventSource | null>(null);
  const retryTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);
  const retryCountRef = useRef(0);
  const onMessageRef = useRef(onMessage);
  onMessageRef.current = onMessage;

  const connect = useCallback(async () => {
    if (!enabled) return;

    const sseToken = await fetchSSEToken();
    const separator = url.includes('?') ? '&' : '?';
    const fullUrl = sseToken ? `/api${url}${separator}token=${sseToken}` : `/api${url}`;

    try {
      const es = new EventSource(fullUrl);
      eventSourceRef.current = es;

      es.onopen = () => {
        setConnected(true);
        setError(null);
        retryCountRef.current = 0;
      };

      es.onmessage = (event) => {
        try {
          const parsed = JSON.parse(event.data);
          setData(parsed);
          onMessageRef.current?.(event);
        } catch {
          setData(event.data as T);
        }
      };

      es.onerror = () => {
        es.close();
        setConnected(false);
        setError(new Error('SSE connection lost'));

        const delay = Math.min(1000 * Math.pow(2, retryCountRef.current), 30000);
        retryCountRef.current += 1;
        retryTimeoutRef.current = setTimeout(connect, delay);
      };
    } catch (err) {
      setError(err instanceof Error ? err : new Error('Failed to connect'));
    }
  }, [url, enabled]);

  useEffect(() => {
    connect();
    return () => {
      eventSourceRef.current?.close();
      if (retryTimeoutRef.current) clearTimeout(retryTimeoutRef.current);
    };
  }, [connect]);

  const disconnect = useCallback(() => {
    eventSourceRef.current?.close();
    if (retryTimeoutRef.current) clearTimeout(retryTimeoutRef.current);
    setConnected(false);
  }, []);

  return { data, connected, error, disconnect };
}
