import { useEffect, useRef, useState, useMemo } from 'react';

export interface LiveBlogStreamEvent {
  type: 'connected' | 'update' | 'status-change' | 'pin-update' | 'error';
  data: unknown;
  clientId?: string;
}

export interface LiveBlogStreamOptions {
  autoReconnect?: boolean;
  reconnectInterval?: number;
  maxReconnectAttempts?: number;
}

export function useLiveBlogStream(
  liveBlogId: string,
  options: LiveBlogStreamOptions = {}
) {
  const defaultOptions = useMemo((): LiveBlogStreamOptions => ({
    autoReconnect: true,
    reconnectInterval: 3000,
    maxReconnectAttempts: 10,
  }), []);
  
  const mergedOptions = useMemo(() => ({ ...defaultOptions, ...options }), [options, defaultOptions]);
  const [isConnected, setIsConnected] = useState(false);
  const [lastEvent, setLastEvent] = useState<LiveBlogStreamEvent | null>(null);
  const [connectionError, setConnectionError] = useState<string | null>(null);
  const [reconnectAttempts, setReconnectAttempts] = useState(0);

  const eventSourceRef = useRef<EventSource | null>(null);
  const reconnectTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastEventIdRef = useRef<string | null>(null);
  const optionsRef = useRef(mergedOptions);
  const reconnectAttemptsRef = useRef(reconnectAttempts);

  // Update refs when props change
  useEffect(() => {
    optionsRef.current = mergedOptions;
  }, [mergedOptions]);

  useEffect(() => {
    reconnectAttemptsRef.current = reconnectAttempts;
  }, [reconnectAttempts]);

  useEffect(() => {
    if (!liveBlogId) return;

    const disconnect = () => {
      if (eventSourceRef.current) {
        eventSourceRef.current.close();
        eventSourceRef.current = null;
      }
      if (reconnectTimeoutRef.current) {
        clearTimeout(reconnectTimeoutRef.current);
        reconnectTimeoutRef.current = null;
      }
      setIsConnected(false);
      setReconnectAttempts(0);
      console.log('Disconnected from live blog stream');
    };

    const createConnection = () => {
      // Close existing connection if any
      if (eventSourceRef.current) {
        eventSourceRef.current.close();
      }

      const url = new URL(`${import.meta.env.VITE_API_URL}/live-blogs/${liveBlogId}/stream`, window.location.origin);
      
      if (lastEventIdRef.current) {
        url.searchParams.set('last-event-id', lastEventIdRef.current);
      }

      try {
        eventSourceRef.current = new EventSource(url.toString());

        eventSourceRef.current.onopen = () => {
          setIsConnected(true);
          setConnectionError(null);
          setReconnectAttempts(0);
          console.log(`Connected to live blog stream for ${liveBlogId}`);
        };

        eventSourceRef.current.onmessage = (event) => {
          try {
            const parsedEvent: LiveBlogStreamEvent = JSON.parse(event.data);
            setLastEvent(parsedEvent);

            // Store last event ID for reconnection
            if (event.lastEventId) {
              lastEventIdRef.current = event.lastEventId;
            }

            // Handle different event types
            switch (parsedEvent.type) {
              case 'connected':
                console.log('Stream connected:', parsedEvent.clientId);
                break;
              case 'update':
                console.log('New update received:', parsedEvent.data);
                break;
              case 'status-change':
                console.log('Status change received:', parsedEvent.data);
                break;
              case 'pin-update':
                console.log('Pin update received:', parsedEvent.data);
                break;
              default:
                console.log('Unknown event type:', parsedEvent.type);
            }
          } catch (error) {
            console.error('Error parsing SSE event:', error);
            setLastEvent({
              type: 'error',
              data: 'Failed to parse server event',
            });
          }
        };

        eventSourceRef.current.onerror = () => {
          console.error('SSE connection error');
          setIsConnected(false);
          setConnectionError('Connection to live blog lost');

          // Attempt reconnection if enabled and within limits
          if (optionsRef.current.autoReconnect && reconnectAttemptsRef.current < (optionsRef.current.maxReconnectAttempts || 10)) {
            const nextAttempt = reconnectAttemptsRef.current + 1;
            setReconnectAttempts(nextAttempt);
            reconnectTimeoutRef.current = setTimeout(() => {
              console.log(`Attempting reconnection (${nextAttempt}/${optionsRef.current.maxReconnectAttempts || 10})`);
              createConnection();
            }, optionsRef.current.reconnectInterval || 3000);
          } else if (reconnectAttemptsRef.current >= (optionsRef.current.maxReconnectAttempts || 10)) {
            setConnectionError('Failed to reconnect after multiple attempts');
          }
        };

      } catch (error) {
        console.error('Failed to create EventSource connection:', error);
        setConnectionError('Failed to connect to live blog stream');
        setIsConnected(false);
      }
    };

    createConnection();

    return () => {
      disconnect();
    };
  }, [liveBlogId]);

  const manualReconnect = () => {
    setReconnectAttempts(0);
    setConnectionError(null);
    // Trigger reconnection by updating liveBlogId dependency
    // This will cause the useEffect to run again
    if (eventSourceRef.current) {
      eventSourceRef.current.close();
      eventSourceRef.current = null;
    }
    // The useEffect will automatically reconnect
  };

  return {
    isConnected,
    lastEvent,
    connectionError,
    reconnectAttempts,
    connect: manualReconnect,
    disconnect: () => {
      if (eventSourceRef.current) {
        eventSourceRef.current.close();
        eventSourceRef.current = null;
      }
      setIsConnected(false);
    },
  };
}