import React, { createContext, useContext, useEffect, useRef, useState, ReactNode, useCallback } from 'react';
import { useAuthStore } from '../stores/auth.store';
import { useCurrentTenant } from '../stores/tenant.store';
// Toast notifications disabled - imports commented out
// import { showToast } from '../utils/toast';
// import i18n from '../i18n';
// import { getTenantCurrencySymbol } from '../hooks/useTenantCurrency';

interface SSEEvent {
  type: string;
  data: any;
  timestamp: string;
}

interface SSEContextType {
  isConnected: boolean;
  lastEvent: SSEEvent | null;
  connect: () => void;
  disconnect: () => void;
  addEventListener: (eventType: string, callback: (data: any) => void) => () => void;
}

export const SSEContext = createContext<SSEContextType | undefined>(undefined);

export const useSSE = () => {
  const context = useContext(SSEContext);
  if (context === undefined) {
    throw new Error('useSSE must be used within an SSEProvider');
  }
  return context;
};

interface SSEProviderProps {
  children: ReactNode;
}

export const SSEProvider: React.FC<SSEProviderProps> = ({ children }) => {
  const [isConnected, setIsConnected] = useState(false);
  const [lastEvent, setLastEvent] = useState<SSEEvent | null>(null);

  const eventSourceRef = useRef<EventSource | null>(null);
  const eventListenersRef = useRef<Map<string, Set<(data: any) => void>>>(new Map());
  const reconnectTimeoutRef = useRef<NodeJS.Timeout>();
  const reconnectAttempts = useRef(0);

  // Global deduplication: Track processed event IDs to prevent duplicate callbacks
  const processedEventIdsRef = useRef<Set<string>>(new Set());

  const { isAuthenticated, token } = useAuthStore();
  const currentTenant = useCurrentTenant();

  const connect = () => {
    // Check if we're in demo mode
    const isDemoMode = localStorage.getItem('demo_mode') === 'true';
    const demoSessionId = localStorage.getItem('demo_session_id');

    // For demo mode, we need demo_session_id and tenant
    // For regular mode, we need token and authentication
    if (isDemoMode) {
      if (!demoSessionId || !currentTenant?.id || eventSourceRef.current) {
        console.log('Demo mode: Missing demo session ID or tenant ID for SSE connection');
        return;
      }
    } else {
      if (!isAuthenticated || !token || eventSourceRef.current) {
        console.log('Regular mode: Not authenticated or missing token for SSE connection');
        return;
      }

      // Skip SSE connection for mock tokens in development mode
      if (token === 'mock-jwt-token') {
        console.log('SSE connection skipped for mock token');
        return;
      }
    }

    if (!currentTenant?.id) {
      console.log('No tenant ID available, skipping SSE connection');
      return;
    }

    try {
      // Connect to gateway SSE endpoint with token/demo_session_id and tenant_id
      // Use same protocol and host as the current page to avoid CORS and mixed content issues
      const protocol = window.location.protocol;
      const host = window.location.host;

      let sseUrl: string;
      if (isDemoMode && demoSessionId) {
        // For demo mode, use demo_session_id instead of token
        sseUrl = `${protocol}//${host}/api/v1/events?demo_session_id=${encodeURIComponent(demoSessionId)}&tenant_id=${currentTenant.id}`;
        console.log('Connecting to SSE endpoint (demo mode):', sseUrl);
      } else {
        // For regular mode, use JWT token
        sseUrl = `${protocol}//${host}/api/v1/events?token=${encodeURIComponent(token!)}&tenant_id=${currentTenant.id}`;
        console.log('Connecting to SSE endpoint (regular mode):', sseUrl);
      }

      const eventSource = new EventSource(sseUrl, {
        withCredentials: true,
      });

      eventSource.onopen = () => {
        console.log('SSE connection opened');
        setIsConnected(true);
        reconnectAttempts.current = 0;

        // Clear processed event IDs on new connection to allow fresh state from server
        // This ensures events are processed again after reconnection or navigation
        processedEventIdsRef.current.clear();
        console.log('🔄 [SSE] Cleared processed event IDs cache on connection open');

        if (reconnectTimeoutRef.current) {
          clearTimeout(reconnectTimeoutRef.current);
          reconnectTimeoutRef.current = undefined;
        }
      };

      // Handle connection confirmation from gateway
      eventSource.addEventListener('connection', (event) => {
        try {
          const data = JSON.parse(event.data);
          console.log('SSE connection confirmed:', data);
        } catch (error) {
          console.error('Error parsing connection event:', error);
        }
      });

      // Handle heartbeat events (keepalive)
      eventSource.addEventListener('heartbeat', (event) => {
        try {
          const data = JSON.parse(event.data);
          console.log('SSE heartbeat received:', data.timestamp);
        } catch (error) {
          console.error('Error parsing heartbeat event:', error);
        }
      });

      // Handle alert events (enriched alerts from alert-processor)
      eventSource.addEventListener('alert', (event) => {
        try {
          const data = JSON.parse(event.data);

          // GLOBAL DEDUPLICATION: Skip if this event was already processed
          if (data.id && processedEventIdsRef.current.has(data.id)) {
            console.log('⏭️ [SSE] Skipping duplicate alert:', data.id);
            return;
          }

          // Mark event as processed
          if (data.id) {
            processedEventIdsRef.current.add(data.id);
            // Limit cache size (keep last 1000 event IDs)
            if (processedEventIdsRef.current.size > 1000) {
              const firstId = Array.from(processedEventIdsRef.current)[0];
              processedEventIdsRef.current.delete(firstId);
            }
          }

          const sseEvent: SSEEvent = {
            type: 'alert',
            data,
            timestamp: data.timestamp || new Date().toISOString(),
          };

          setLastEvent(sseEvent);

          // Toast notifications disabled for SSE alerts
          // Code below kept for potential future re-enablement
          /*
          // Determine toast type based on enriched priority_level and type_class
          let toastType: 'info' | 'success' | 'warning' | 'error' = 'info';

          // Use success toast for prevented_issue type (AI already handled)
          if (data.type_class === 'prevented_issue') {
            toastType = 'success';
          } else if (data.priority_level === 'critical') {
            toastType = 'error';
          } else if (data.priority_level === 'important') {
            toastType = 'warning';
          } else if (data.priority_level === 'standard') {
            toastType = 'info';
          }

          // Translate title and message using i18n keys
          let title = 'Alerta';
          let message = 'Nueva alerta';

          if (data.i18n?.title_key) {
            // Extract namespace from key (e.g., "alerts.critical_stock_shortage.title" -> namespace: "alerts", key: "critical_stock_shortage.title")
            const titleParts = data.i18n.title_key.split('.');
            const titleNamespace = titleParts[0];
            const titleKey = titleParts.slice(1).join('.');

            title = String(i18n.t(titleKey, {
              ns: titleNamespace,
              ...data.i18n.title_params,
              defaultValue: data.i18n.title_key
            }));
          }

          if (data.i18n?.message_key) {
            // Extract namespace from key (e.g., "alerts.critical_stock_shortage.message_generic" -> namespace: "alerts", key: "critical_stock_shortage.message_generic")
            const messageParts = data.i18n.message_key.split('.');
            const messageNamespace = messageParts[0];
            const messageKey = messageParts.slice(1).join('.');

            message = String(i18n.t(messageKey, {
              ns: messageNamespace,
              ...data.i18n.message_params,
              defaultValue: data.i18n.message_key
            }));
          }

          const duration = data.priority_level === 'critical' ? 0 : 5000;

          // Add financial impact to message if available
          if (data.business_impact?.financial_impact_eur) {
            const currencySymbol = getTenantCurrencySymbol(currentTenant?.currency);
            message = `${message} • ${currencySymbol}${data.business_impact.financial_impact_eur} en riesgo`;
          }

          showToast[toastType](message, { title, duration });
          */

          // Trigger listeners with enriched alert data
          // Wrap in queueMicrotask to prevent setState during render warnings
          const listeners = eventListenersRef.current.get('alert');
          console.log('📤 [SSEContext] Notifying alert listeners:', {
            listenerCount: listeners?.size || 0,
            eventId: data.id,
            eventType: data.event_type || data.type,
          });
          if (listeners) {
            listeners.forEach(callback => {
              queueMicrotask(() => callback(data));
            });
          }
        } catch (error) {
          console.error('Error parsing alert event:', error);
        }
      });

      // Handle notification events (from various services)
      eventSource.addEventListener('notification', (event) => {
        try {
          const data = JSON.parse(event.data);

          // GLOBAL DEDUPLICATION: Skip if this event was already processed
          if (data.id && processedEventIdsRef.current.has(data.id)) {
            console.log('⏭️ [SSE] Skipping duplicate notification:', data.id);
            return;
          }

          // Mark event as processed
          if (data.id) {
            processedEventIdsRef.current.add(data.id);
            if (processedEventIdsRef.current.size > 1000) {
              const firstId = Array.from(processedEventIdsRef.current)[0];
              processedEventIdsRef.current.delete(firstId);
            }
          }

          const sseEvent: SSEEvent = {
            type: 'notification',
            data,
            timestamp: data.timestamp || new Date().toISOString(),
          };

          setLastEvent(sseEvent);

          // Toast notifications disabled for SSE notifications
          // Code below kept for potential future re-enablement
          /*
          // Determine toast type based on notification priority or type
          let toastType: 'info' | 'success' | 'warning' | 'error' = 'info';

          // Use type_class if available from the new event architecture
          if (data.type_class) {
            if (data.type_class === 'success' || data.type_class === 'completed') {
              toastType = 'success';
            } else if (data.type_class === 'error') {
              toastType = 'error';
            } else if (data.type_class === 'warning') {
              toastType = 'warning';
            } else if (data.type_class === 'info') {
              toastType = 'info';
            }
          } else {
            // Fallback to priority_level for legacy compatibility
            if (data.priority_level === 'critical') {
              toastType = 'error';
            } else if (data.priority_level === 'important') {
              toastType = 'warning';
            } else if (data.priority_level === 'standard') {
              toastType = 'info';
            }
          }

          // Translate title and message using i18n keys
          let title = 'Notificación';
          let message = 'Nueva notificación recibida';

          if (data.i18n?.title_key) {
            // Extract namespace from key
            const titleParts = data.i18n.title_key.split('.');
            const titleNamespace = titleParts[0];
            const titleKey = titleParts.slice(1).join('.');

            title = String(i18n.t(titleKey, {
              ns: titleNamespace,
              ...data.i18n.title_params,
              defaultValue: data.i18n.title_key
            }));
          } else if (data.title || data.subject) {
            // Fallback to legacy fields if i18n not available
            title = data.title || data.subject;
          }

          if (data.i18n?.message_key) {
            // Extract namespace from key
            const messageParts = data.i18n.message_key.split('.');
            const messageNamespace = messageParts[0];
            const messageKey = messageParts.slice(1).join('.');

            message = String(i18n.t(messageKey, {
              ns: messageNamespace,
              ...data.i18n.message_params,
              defaultValue: data.i18n.message_key
            }));
          } else if (data.message || data.content || data.description) {
            // Fallback to legacy fields if i18n not available
            message = data.message || data.content || data.description;
          }

          // Add entity context to message if available
          if (data.entity_links && Object.keys(data.entity_links).length > 0) {
            const entityInfo = Object.entries(data.entity_links)
              .map(([type, id]) => `${type}: ${id}`)
              .join(', ');
            message = `${message} (${entityInfo})`;
          }

          // Add state change information if available
          if (data.old_state && data.new_state) {
            message = `${message} - ${data.old_state} → ${data.new_state}`;
          }

          const duration = data.priority_level === 'critical' ? 0 : 5000;

          showToast[toastType](message, { title, duration });
          */

          // Trigger listeners with notification data
          // Wrap in queueMicrotask to prevent setState during render warnings
          const listeners = eventListenersRef.current.get('notification');
          if (listeners) {
            listeners.forEach(callback => {
              queueMicrotask(() => callback(data));
            });
          }
        } catch (error) {
          console.error('Error parsing notification event:', error);
        }
      });

      // Handle recommendation events (AI-driven insights)
      eventSource.addEventListener('recommendation', (event) => {
        try {
          const data = JSON.parse(event.data);

          // GLOBAL DEDUPLICATION: Skip if this event was already processed
          if (data.id && processedEventIdsRef.current.has(data.id)) {
            console.log('⏭️ [SSE] Skipping duplicate recommendation:', data.id);
            return;
          }

          // Mark event as processed
          if (data.id) {
            processedEventIdsRef.current.add(data.id);
            if (processedEventIdsRef.current.size > 1000) {
              const firstId = Array.from(processedEventIdsRef.current)[0];
              processedEventIdsRef.current.delete(firstId);
            }
          }

          const sseEvent: SSEEvent = {
            type: 'recommendation',
            data,
            timestamp: data.timestamp || new Date().toISOString(),
          };

          setLastEvent(sseEvent);

          // Toast notifications disabled for SSE recommendations
          // Code below kept for potential future re-enablement
          /*
          // Recommendations are typically positive insights
          let toastType: 'info' | 'success' | 'warning' | 'error' = 'info';

          // Use type_class if available from the new event architecture
          if (data.type_class) {
            if (data.type_class === 'opportunity' || data.type_class === 'insight') {
              toastType = 'success';
            } else if (data.type_class === 'error') {
              toastType = 'error';
            } else if (data.type_class === 'warning') {
              toastType = 'warning';
            } else if (data.type_class === 'info') {
              toastType = 'info';
            }
          } else {
            // Fallback to priority_level for legacy compatibility
            if (data.priority_level === 'critical') {
              toastType = 'error';
            } else if (data.priority_level === 'important') {
              toastType = 'warning';
            } else {
              toastType = 'info';
            }
          }

          // Translate title and message using i18n keys
          let title = 'Recomendación';
          let message = 'Nueva recomendación del sistema AI';

          if (data.i18n?.title_key) {
            // Extract namespace from key
            const titleParts = data.i18n.title_key.split('.');
            const titleNamespace = titleParts[0];
            const titleKey = titleParts.slice(1).join('.');

            title = String(i18n.t(titleKey, {
              ns: titleNamespace,
              ...data.i18n.title_params,
              defaultValue: data.i18n.title_key
            }));
          } else if (data.title) {
            // Fallback to legacy field if i18n not available
            title = data.title;
          }

          if (data.i18n?.message_key) {
            // Extract namespace from key
            const messageParts = data.i18n.message_key.split('.');
            const messageNamespace = messageParts[0];
            const messageKey = messageParts.slice(1).join('.');

            message = String(i18n.t(messageKey, {
              ns: messageNamespace,
              ...data.i18n.message_params,
              defaultValue: data.i18n.message_key
            }));
          } else if (data.message) {
            // Fallback to legacy field if i18n not available
            message = data.message;
          }

          // Add estimated impact if available
          if (data.estimated_impact) {
            const impact = data.estimated_impact;
            if (impact.savings_eur) {
              const currencySymbol = getTenantCurrencySymbol(currentTenant?.currency);
              message = `${message} • ${currencySymbol}${impact.savings_eur} de ahorro estimado`;
            } else if (impact.risk_reduction_percent) {
              message = `${message} • ${impact.risk_reduction_percent}% reducción de riesgo`;
            }
          }

          const duration = 5000; // Recommendations are typically informational

          showToast[toastType](message, { title, duration });
          */

          // Trigger listeners with recommendation data
          // Wrap in queueMicrotask to prevent setState during render warnings
          const listeners = eventListenersRef.current.get('recommendation');
          console.log('📤 [SSEContext] Notifying recommendation listeners:', {
            listenerCount: listeners?.size || 0,
            eventId: data.id,
            eventType: data.event_type || data.type,
          });
          if (listeners) {
            listeners.forEach(callback => {
              queueMicrotask(() => callback(data));
            });
          }
        } catch (error) {
          console.error('Error parsing recommendation event:', error);
        }
      });

      eventSource.onerror = (error) => {
        console.error('SSE connection error:', error);
        setIsConnected(false);
        
        if (eventSource.readyState === EventSource.CLOSED) {
          // Attempt reconnection with exponential backoff
          const delay = Math.min(1000 * Math.pow(2, reconnectAttempts.current), 30000);
          reconnectAttempts.current++;
          
          reconnectTimeoutRef.current = setTimeout(() => {
            if (isAuthenticated && token) {
              connect();
            }
          }, delay);
        }
      };


      eventSourceRef.current = eventSource;
    } catch (error) {
      console.error('Failed to establish SSE connection:', error);
      setIsConnected(false);
    }
  };

  const disconnect = () => {
    if (eventSourceRef.current) {
      eventSourceRef.current.close();
      eventSourceRef.current = null;
    }
    
    if (reconnectTimeoutRef.current) {
      clearTimeout(reconnectTimeoutRef.current);
      reconnectTimeoutRef.current = undefined;
    }
    
    setIsConnected(false);
    reconnectAttempts.current = 0;
  };

  // Memoize addEventListener to prevent unnecessary effect re-runs in consumers
  const addEventListener = useCallback((eventType: string, callback: (data: any) => void) => {
    if (!eventListenersRef.current.has(eventType)) {
      eventListenersRef.current.set(eventType, new Set());
    }

    eventListenersRef.current.get(eventType)!.add(callback);

    // Return cleanup function
    return () => {
      const listeners = eventListenersRef.current.get(eventType);
      if (listeners) {
        listeners.delete(callback);
        if (listeners.size === 0) {
          eventListenersRef.current.delete(eventType);
        }
      }
    };
  }, []); // No dependencies - uses only refs

  // Connect when authenticated, disconnect when not or when tenant changes
  useEffect(() => {
    const isDemoMode = localStorage.getItem('demo_mode') === 'true';
    const demoSessionId = localStorage.getItem('demo_session_id');

    // For demo mode: connect if we have demo_session_id and tenant
    // For regular mode: connect if authenticated with token and tenant
    const shouldConnect = isDemoMode
      ? (demoSessionId && currentTenant)
      : (isAuthenticated && token && currentTenant);

    if (shouldConnect) {
      connect();
    } else {
      disconnect();
    }

    return () => {
      disconnect();
    };
  }, [isAuthenticated, token, currentTenant?.id]);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      disconnect();
    };
  }, []);

  // Context value - consumers should extract only what they need
  // addEventListener is now stable (wrapped in useCallback)
  const contextValue: SSEContextType = {
    isConnected,
    lastEvent,
    connect,
    disconnect,
    addEventListener,
  };

  return (
    <SSEContext.Provider value={contextValue}>
      {children}
    </SSEContext.Provider>
  );
};