import { useEffect, useRef, useCallback } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'react-hot-toast';
import { useCurrentUser } from './useAuth';
import { getBaseDomain } from '../utils/domain';
import { getCookie } from '../utils/cookies';

interface TicketWebSocketMessage {
  type: 'new_ticket' | 'ticket_update' | 'ticket_deleted' | 'new_comment' | 'ticket_assigned' | 'ticket_status_changed';
  ticket_id: number | string;
  subject?: string;
  ticket_type?: string;
  priority?: string;
  status?: string;
  creator_name?: string;
  assignee_name?: string;
  comment_id?: number | string;
  author_name?: string;
  message: string;
}

interface UseTicketWebSocketOptions {
  showToasts?: boolean;
  onNewTicket?: (data: TicketWebSocketMessage) => void;
  onTicketUpdate?: (data: TicketWebSocketMessage) => void;
  onNewComment?: (data: TicketWebSocketMessage) => void;
}

/**
 * Custom hook to manage WebSocket connection for real-time ticket updates.
 * Automatically invalidates React Query cache when ticket changes occur.
 */
export const useTicketWebSocket = (options: UseTicketWebSocketOptions = {}) => {
  const { showToasts = true, onNewTicket, onTicketUpdate, onNewComment } = options;
  const wsRef = useRef<WebSocket | null>(null);
  const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
  const reconnectAttempts = useRef(0);
  const maxReconnectAttempts = 5;
  const { data: user } = useCurrentUser();
  const queryClient = useQueryClient();

  const handleMessage = useCallback((event: MessageEvent) => {
    try {
      const data: TicketWebSocketMessage = JSON.parse(event.data);
      console.log('Ticket WebSocket message received:', data);

      switch (data.type) {
        case 'new_ticket':
          // Invalidate ticket list to refetch
          queryClient.invalidateQueries({ queryKey: ['tickets'] });
          if (showToasts) {
            toast.success(data.message || `New ticket: ${data.subject}`, {
              duration: 5000,
              position: 'top-right',
            });
          }
          onNewTicket?.(data);
          break;

        case 'ticket_update':
        case 'ticket_assigned':
        case 'ticket_status_changed':
          // Invalidate specific ticket and list
          queryClient.invalidateQueries({ queryKey: ['tickets'] });
          if (data.ticket_id) {
            queryClient.invalidateQueries({ queryKey: ['tickets', String(data.ticket_id)] });
          }
          if (showToasts && data.type !== 'ticket_update') {
            toast(data.message || 'Ticket updated', {
              duration: 4000,
              position: 'top-right',
              icon: '🎫',
            });
          }
          onTicketUpdate?.(data);
          break;

        case 'ticket_deleted':
          // Invalidate ticket list
          queryClient.invalidateQueries({ queryKey: ['tickets'] });
          if (data.ticket_id) {
            // Remove specific ticket from cache
            queryClient.removeQueries({ queryKey: ['tickets', String(data.ticket_id)] });
          }
          break;

        case 'new_comment':
          // Invalidate comments for the ticket
          if (data.ticket_id) {
            queryClient.invalidateQueries({ queryKey: ['ticketComments', String(data.ticket_id)] });
            queryClient.invalidateQueries({ queryKey: ['tickets', String(data.ticket_id)] });
          }
          if (showToasts) {
            toast(data.message || 'New comment on ticket', {
              duration: 4000,
              position: 'top-right',
              icon: '💬',
            });
          }
          onNewComment?.(data);
          break;

        default:
          console.log('Unknown ticket WebSocket message type:', data.type);
      }
    } catch (error) {
      console.error('Error parsing ticket WebSocket message:', error);
    }
  }, [queryClient, showToasts, onNewTicket, onTicketUpdate, onNewComment]);

  const connect = useCallback(() => {
    if (!user || !user.id) {
      return;
    }

    // Determine WebSocket URL using same logic as API config
    const baseDomain = getBaseDomain();
    const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';

    // For localhost or lvh.me, use port 8000. In production, no port (Traefik handles it)
    const isDev = baseDomain === 'localhost' || baseDomain === 'lvh.me';
    const port = isDev ? ':8000' : '';

    const token = getCookie('access_token');
    const wsUrl = `${protocol}//api.${baseDomain}${port}/ws/tickets/?token=${token}`;

    console.log('Connecting to ticket WebSocket:', wsUrl);

    try {
      wsRef.current = new WebSocket(wsUrl);

      wsRef.current.onopen = () => {
        console.log('Ticket WebSocket connected');
        reconnectAttempts.current = 0; // Reset reconnect attempts on successful connection
      };

      wsRef.current.onmessage = handleMessage;

      wsRef.current.onclose = (event) => {
        console.log('Ticket WebSocket disconnected:', event.code, event.reason);

        // Attempt to reconnect with exponential backoff
        if (user && user.id && reconnectAttempts.current < maxReconnectAttempts) {
          const delay = Math.min(1000 * Math.pow(2, reconnectAttempts.current), 30000);
          reconnectAttempts.current += 1;
          console.log(`Attempting to reconnect ticket WebSocket in ${delay}ms (attempt ${reconnectAttempts.current})`);

          reconnectTimeoutRef.current = setTimeout(() => {
            connect();
          }, delay);
        }
      };

      wsRef.current.onerror = (error) => {
        console.error('Ticket WebSocket error:', error);
      };
    } catch (error) {
      console.error('Failed to create ticket WebSocket:', error);
    }
  }, [user, handleMessage]);

  useEffect(() => {
    connect();

    return () => {
      // Clear reconnect timeout
      if (reconnectTimeoutRef.current) {
        clearTimeout(reconnectTimeoutRef.current);
      }
      // Close WebSocket
      if (wsRef.current) {
        wsRef.current.close();
        wsRef.current = null;
      }
    };
  }, [connect]);

  // Return connection status for debugging
  return {
    isConnected: wsRef.current?.readyState === WebSocket.OPEN,
  };
};
