// Notification Context and Provider
// Manages notification state, SSE subscription, and notification actions

const { useState, useCallback, useEffect, createContext, useContext, useRef } = React;

// Token key constant (same value as in api.js and AuthContext)
const NOTIFICATION_TOKEN_KEY = 'rosa_access_token';

const NotificationContext = createContext();

function NotificationProvider({ children }) {
    const toast = useToast();
    const { isAuthenticated, user } = useAuth();
    const [notifications, setNotifications] = useState([]);
    const [unreadCount, setUnreadCount] = useState(0);
    const [loading, setLoading] = useState(false);
    const websocketRef = useRef(null);
    const reconnectTimeoutRef = useRef(null);

    // Get auth headers helper
    const getAuthHeaders = () => {
        const token = localStorage.getItem(NOTIFICATION_TOKEN_KEY);
        return token ? { 'Authorization': `Bearer ${token}` } : {};
    };

    // Fetch notifications from API
    const fetchNotifications = useCallback(async (limit = 20) => {
        if (!isAuthenticated) return;
        
        setLoading(true);
        try {
            const response = await fetch(`/api/notifications?limit=${limit}`, {
                headers: getAuthHeaders(),
            });
            if (response.ok) {
                const data = await response.json();
                setNotifications(data.notifications || []);
                setUnreadCount(data.unread_count || 0);
            }
        } catch (err) {
            console.error('Failed to fetch notifications:', err);
        } finally {
            setLoading(false);
        }
    }, [isAuthenticated]);

    // Fetch just the unread count (lightweight)
    const fetchUnreadCount = useCallback(async () => {
        if (!isAuthenticated) return;
        
        try {
            const response = await fetch('/api/notifications/unread-count', {
                headers: getAuthHeaders(),
            });
            if (response.ok) {
                const data = await response.json();
                setUnreadCount(data.count || 0);
            }
        } catch (err) {
            console.error('Failed to fetch unread count:', err);
        }
    }, [isAuthenticated]);

    // Mark a single notification as read
    const markAsRead = useCallback(async (notificationId) => {
        try {
            const response = await fetch(`/api/notifications/${notificationId}/read`, {
                method: 'POST',
                headers: getAuthHeaders(),
            });
            if (response.ok) {
                const data = await response.json();
                // Update local state
                setNotifications(prev => 
                    prev.map(n => 
                        n.id === notificationId 
                            ? { ...n, is_read: true, read_at: new Date().toISOString() }
                            : n
                    )
                );
                setUnreadCount(prev => Math.max(0, prev - 1));
                return data.notification;
            }
        } catch (err) {
            console.error('Failed to mark notification as read:', err);
        }
        return null;
    }, []);

    // Mark all notifications as read
    const markAllAsRead = useCallback(async () => {
        try {
            const response = await fetch('/api/notifications/read-all', {
                method: 'POST',
                headers: getAuthHeaders(),
            });
            if (response.ok) {
                // Update local state
                setNotifications(prev => 
                    prev.map(n => ({ ...n, is_read: true, read_at: new Date().toISOString() }))
                );
                setUnreadCount(0);
                return true;
            }
        } catch (err) {
            console.error('Failed to mark all notifications as read:', err);
        }
        return false;
    }, []);

    // Delete a notification
    const deleteNotification = useCallback(async (notificationId) => {
        try {
            const response = await fetch(`/api/notifications/${notificationId}`, {
                method: 'DELETE',
                headers: getAuthHeaders(),
            });
            if (response.ok) {
                // Update local state
                setNotifications(prev => {
                    const notification = prev.find(n => n.id === notificationId);
                    if (notification && !notification.is_read) {
                        setUnreadCount(c => Math.max(0, c - 1));
                    }
                    return prev.filter(n => n.id !== notificationId);
                });
                return true;
            }
        } catch (err) {
            console.error('Failed to delete notification:', err);
        }
        return false;
    }, []);

    // Handle incoming real-time notification
    const handleNewNotification = useCallback((notification) => {
        // Add to notifications list (at the beginning)
        setNotifications(prev => [notification, ...prev.slice(0, 49)]);
        setUnreadCount(prev => prev + 1);
        
        // Show toast notification
        toast(notification.title, 'info');
    }, [toast]);

    // Set up WebSocket connection for real-time notifications + polling fallback
    useEffect(() => {
        let pollingInterval = null;

        if (!isAuthenticated) {
            // Clean up if not authenticated
            if (websocketRef.current) {
                websocketRef.current.close();
                websocketRef.current = null;
            }
            if (reconnectTimeoutRef.current) {
                clearTimeout(reconnectTimeoutRef.current);
                reconnectTimeoutRef.current = null;
            }
            return;
        }

        const connect = () => {
            // Close existing connection
            if (websocketRef.current) {
                websocketRef.current.close();
            }

            // Get token for WebSocket authentication
            const token = localStorage.getItem(NOTIFICATION_TOKEN_KEY);
            if (!token) {
                console.warn('No auth token for notification WebSocket');
                return;
            }

            // Determine WebSocket protocol based on current page protocol
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            const host = window.location.host;
            const wsUrl = `${protocol}//${host}/api/notifications/ws`;

            const ws = new WebSocket(wsUrl);
            websocketRef.current = ws;

            ws.onopen = () => {
                console.log('WebSocket connected, sending auth...');
                // Send authentication message
                ws.send(JSON.stringify({
                    type: 'auth',
                    token: token
                }));
            };

            ws.onmessage = (event) => {
                try {
                    const message = JSON.parse(event.data);

                    switch (message.type) {
                        case 'auth_success':
                            console.log('WebSocket authenticated successfully');
                            break;
                        case 'notification':
                            // Handle incoming notification
                            handleNewNotification(message.data);
                            break;
                        case 'heartbeat':
                            // Heartbeat to keep connection alive
                            console.debug('WebSocket heartbeat received');
                            break;
                        case 'error':
                            console.error('WebSocket error from server:', message.message);
                            break;
                        default:
                            console.warn('Unknown WebSocket message type:', message.type);
                    }
                } catch (err) {
                    console.error('Failed to parse WebSocket message:', err);
                }
            };

            ws.onerror = (err) => {
                console.error('WebSocket error:', err);
            };

            ws.onclose = (event) => {
                console.log('WebSocket closed:', event.code, event.reason);
                websocketRef.current = null;

                // Reconnect after 5 seconds if not a normal closure
                if (event.code !== 1000) {
                    reconnectTimeoutRef.current = setTimeout(connect, 5000);
                }
            };
        };

        // Initial connection
        connect();

        // Initial fetch
        fetchNotifications();

        // Also set up polling as fallback (every 30 seconds)
        // This ensures notifications are fetched even if Redis/WebSocket is not working
        pollingInterval = setInterval(() => {
            fetchUnreadCount();
        }, 30000);

        // Cleanup on unmount or auth change
        return () => {
            if (websocketRef.current) {
                websocketRef.current.close();
                websocketRef.current = null;
            }
            if (reconnectTimeoutRef.current) {
                clearTimeout(reconnectTimeoutRef.current);
                reconnectTimeoutRef.current = null;
            }
            if (pollingInterval) {
                clearInterval(pollingInterval);
            }
        };
    }, [isAuthenticated, handleNewNotification, fetchNotifications, fetchUnreadCount]);

    const value = {
        notifications,
        unreadCount,
        loading,
        fetchNotifications,
        fetchUnreadCount,
        markAsRead,
        markAllAsRead,
        deleteNotification,
    };

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

function useNotifications() {
    const context = useContext(NotificationContext);
    if (!context) {
        throw new Error('useNotifications must be used within a NotificationProvider');
    }
    return context;
}

// Export to global scope
window.NotificationContext = NotificationContext;
window.NotificationProvider = NotificationProvider;
window.useNotifications = useNotifications;

