import { useEffect, useRef } from "react";
import { useQueryClient } from "@tanstack/react-query";
import { Logger } from "@/lib/logger";
import { useAuth } from "@/contexts/auth-context";
import { tournamentQueries } from "@/features/tournaments/queries";
import { reactionKeys, reactionQueries } from "@/features/reactions/queries";

const logger = new Logger('ServerEvents');

type SSEEvent = {
  type: string;
  [key: string]: any;
};

type EventHandler = (event: SSEEvent, queryClient: ReturnType<typeof useQueryClient>, currentSessionId?: string) => void;

const eventHandlers: Record<string, EventHandler> = {
  "connected": () => {
    logger.info("New Connection");
  },
  "ping": () => {},
  "heartbeat": () => {},
  "match": (event, queryClient) => {
    queryClient.invalidateQueries(tournamentQueries.details(event.tournamentId))
    queryClient.invalidateQueries(tournamentQueries.current())
  },
  "reaction": (event, queryClient) => {
    queryClient.invalidateQueries(reactionQueries.match(event.matchId));
    queryClient.setQueryData(reactionKeys.match(event.matchId), () => event.reactions);
  }
};

export function useServerEvents() {
  const queryClient = useQueryClient();
  const { user } = useAuth();
  const retryCountRef = useRef(0);
  const shouldConnectRef = useRef(true);
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);

  useEffect(() => {
    if (typeof window === 'undefined') return;
    if (!user?.id) return;

    shouldConnectRef.current = true;
    retryCountRef.current = 0;

    const connectEventSource = () => {
      if (!shouldConnectRef.current) return;


      const eventSource = new EventSource(`/api/events/$`);

      eventSource.onopen = () => {
        retryCountRef.current = 0;
      };

      eventSource.onmessage = (event) => {
        try {
          const data: SSEEvent = JSON.parse(event.data);
          logger.info("Event received", data);

          const handler = eventHandlers[data.type];
          if (handler) {
            handler(data, queryClient, user?.id);
          } else {
            logger.warn(`Unhandled SSE event type: ${data.type}`);
          }
        } catch (error) {
          logger.error("Error parsing SSE message", error);
        }
      };

      eventSource.onerror = (error) => {
        logger.error("SSE connection error", error);
        eventSource.close();

        if (shouldConnectRef.current && retryCountRef.current < 10) {
          retryCountRef.current += 1;
          const delay = Math.min(
            1000 * Math.pow(1.5, retryCountRef.current - 1),
            15000
          );

          logger.info(
            `SSE reconnection attempt ${retryCountRef.current}/10 in ${delay}ms`
          );

          timeoutRef.current = setTimeout(() => {
            if (shouldConnectRef.current) {
              connectEventSource();
            }
          }, delay);
        } else if (retryCountRef.current >= 10) {
          logger.error("SSE max reconnection attempts reached");
        }
      };

      return eventSource;
    };

    const eventSource = connectEventSource();

    return () => {
      logger.info("Closing SSE connection");
      shouldConnectRef.current = false;

      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current);
        timeoutRef.current = null;
      }

      if (eventSource) {
        eventSource.close();
      }
    };
  }, [user?.id]);
}