/**
 * Real-time Notification System
 * 
 * Handles WebSocket connections and updates the UI with new notifications
 */

class NotificationSystem {
    constructor() {
        this.socket = null;
        this.isConnected = false;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectInterval = 5000; // 5 seconds
        this.notifications = [];
        this.unreadCount = 0;
        this.soundEnabled = true;
        this.browserNotificationsEnabled = true;
        this.notificationSound = new Audio('dist/audio/notification.mp3');
        this.userId = null;
        this.userType = null;
    }

    /**
     * Initialize the notification system
     * @param {Object} config Configuration object
     */
    init(config = {}) {
        this.userId = config.userId || null;
        this.userType = config.userType || 'admin';
        this.soundEnabled = config.soundEnabled !== undefined ? config.soundEnabled : true;
        this.browserNotificationsEnabled = config.browserNotificationsEnabled !== undefined ? config.browserNotificationsEnabled : true;
        
        if (!this.userId) {
            console.error('User ID is required to initialize the notification system');
            return;
        }
        
        // Initialize notification elements
        this.initUIElements();
        
        // Load recent notifications from API
        this.loadRecentNotifications();
        
        // Connect to WebSocket server if enabled
        if (config.websocketEnabled !== false) {
            this.connectWebSocket();
        }
        
        // Request browser notification permission
        if (this.browserNotificationsEnabled) {
            this.requestNotificationPermission();
        }
        
        // Set up refresh interval for notifications
        setInterval(() => this.loadRecentNotifications(), 60000); // Refresh every minute
    }

    /**
     * Initialize UI elements
     */
    initUIElements() {
        // Set up notification dropdown event listener
        $('#notificationDropdown').on('show.bs.dropdown', () => {
            this.loadRecentNotifications();
        });
        
        // Mark notifications as read when clicked
        $(document).on('click', '.notification-item', (e) => {
            const notificationId = $(e.currentTarget).data('notification-id');
            if (notificationId) {
                this.markAsRead(notificationId);
            }
        });
    }

    /**
     * Connect to WebSocket server
     */
    connectWebSocket() {
        try {
            // Use secure WebSocket if the page is loaded over HTTPS
            const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
            const host = window.location.hostname;
            const port = 8080; // WebSocket server port
            
            this.socket = new WebSocket(`${protocol}://${host}:${port}`);
            
            // Set up event handlers
            this.socket.onopen = () => this.handleSocketOpen();
            this.socket.onmessage = (event) => this.handleSocketMessage(event);
            this.socket.onclose = () => this.handleSocketClose();
            this.socket.onerror = (error) => this.handleSocketError(error);
        } catch (error) {
            console.error('WebSocket connection error:', error);
        }
    }

    /**
     * Handle WebSocket connection open
     */
    handleSocketOpen() {
        console.log('WebSocket connection established');
        this.isConnected = true;
        this.reconnectAttempts = 0;
        
        // Authenticate
        this.sendSocketMessage({
            action: 'auth',
            user_id: this.userId,
            user_type: this.userType,
            auth_token: this.getAuthToken()
        });
    }

    /**
     * Handle WebSocket message
     * @param {MessageEvent} event WebSocket message event
     */
    handleSocketMessage(event) {
        try {
            const data = JSON.parse(event.data);
            console.log('WebSocket message received:', data);
            
            if (data.type === 'auth' && data.status === 'success') {
                console.log('WebSocket authentication successful');
            }
            
            if (data.type === 'notification') {
                this.handleNewNotification(data.data);
            }
            
            if (data.type === 'notifications') {
                data.data.forEach(notification => {
                    this.handleNewNotification(notification);
                });
            }
        } catch (error) {
            console.error('Error processing WebSocket message:', error);
        }
    }

    /**
     * Handle WebSocket connection close
     */
    handleSocketClose() {
        console.log('WebSocket connection closed');
        this.isConnected = false;
        
        // Attempt to reconnect
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.reconnectAttempts++;
            console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
            
            setTimeout(() => {
                this.connectWebSocket();
            }, this.reconnectInterval);
        } else {
            console.error('Maximum reconnection attempts reached');
        }
    }

    /**
     * Handle WebSocket error
     * @param {Event} error WebSocket error event
     */
    handleSocketError(error) {
        console.error('WebSocket error:', error);
    }

    /**
     * Send a message through the WebSocket
     * @param {Object} message Message to send
     */
    sendSocketMessage(message) {
        if (this.isConnected) {
            this.socket.send(JSON.stringify(message));
        } else {
            console.error('Cannot send message, WebSocket is not connected');
        }
    }

    /**
     * Load recent notifications from API
     */
    loadRecentNotifications() {
        $.ajax({
            url: 'api/notifications/recent.php',
            method: 'GET',
            dataType: 'json',
            success: (response) => {
                if (response.success) {
                    this.notifications = response.data.notifications;
                    this.unreadCount = response.data.unread_count;
                    this.updateNotificationUI();
                } else {
                    console.error('Error loading notifications:', response.message);
                }
            },
            error: (xhr, status, error) => {
                console.error('AJAX error loading notifications:', error);
            }
        });
    }

    /**
     * Handle a new notification
     * @param {Object} notification Notification object
     */
    handleNewNotification(notification) {
        // Check if we already have this notification
        const existingIndex = this.notifications.findIndex(n => n.id === notification.id);
        
        if (existingIndex === -1) {
            // Add to the beginning of the array
            this.notifications.unshift(notification);
            
            // Limit to 10 notifications in the UI
            if (this.notifications.length > 10) {
                this.notifications.pop();
            }
            
            // Increment unread count
            this.unreadCount++;
            
            // Update UI
            this.updateNotificationUI();
            
            // Play sound if enabled
            if (this.soundEnabled) {
                this.playNotificationSound();
            }
            
            // Show browser notification if enabled
            if (this.browserNotificationsEnabled) {
                this.showBrowserNotification(notification);
            }
        }
    }

    /**
     * Update notification UI elements
     */
    updateNotificationUI() {
        // Update notification count
        $('#notificationCount').text(this.unreadCount > 0 ? this.unreadCount : '');
        
        // Update header
        $('#notificationHeader').text(this.unreadCount > 0 ? `${this.unreadCount} Notifications` : 'No New Notifications');
        
        // Update notification items
        const $notificationItems = $('#notificationItems');
        $notificationItems.empty();
        
        if (this.notifications.length === 0) {
            $notificationItems.append(`
                <a href="#" class="dropdown-item">
                    <i class="fas fa-check mr-2"></i> No new notifications
                </a>
            `);
        } else {
            this.notifications.forEach(notification => {
                const icon = this.getNotificationIcon(notification.type);
                const timeAgo = this.formatTimeAgo(notification.created_at);
                const isRead = notification.is_read ? 'read' : 'unread';
                
                $notificationItems.append(`
                    <a href="#" class="dropdown-item notification-item ${isRead}" data-notification-id="${notification.id}">
                        <i class="${icon} mr-2"></i> ${notification.title}
                        <span class="float-right text-muted text-sm">${timeAgo}</span>
                        <p class="text-sm">${notification.message.substring(0, 60)}${notification.message.length > 60 ? '...' : ''}</p>
                    </a>
                    <div class="dropdown-divider"></div>
                `);
            });
        }
    }

    /**
     * Mark a notification as read
     * @param {number} notificationId Notification ID
     */
    markAsRead(notificationId) {
        $.ajax({
            url: 'api/notifications/mark_read.php',
            method: 'POST',
            data: {
                notification_id: notificationId
            },
            dataType: 'json',
            success: (response) => {
                if (response.success) {
                    // Update local notification status
                    const notification = this.notifications.find(n => n.id === notificationId);
                    if (notification && !notification.is_read) {
                        notification.is_read = true;
                        notification.read_at = new Date().toISOString();
                        this.unreadCount = Math.max(0, this.unreadCount - 1);
                        this.updateNotificationUI();
                    }
                }
            }
        });
    }

    /**
     * Get notification icon class based on type
     * @param {string} type Notification type
     * @returns {string} Icon class
     */
    getNotificationIcon(type) {
        switch (type) {
            case 'info':
                return 'fas fa-info-circle text-info';
            case 'success':
                return 'fas fa-check-circle text-success';
            case 'warning':
                return 'fas fa-exclamation-triangle text-warning';
            case 'error':
                return 'fas fa-times-circle text-danger';
            case 'announcement':
                return 'fas fa-bullhorn text-primary';
            case 'event':
                return 'fas fa-calendar-alt text-indigo';
            case 'payment':
                return 'fas fa-money-bill-wave text-success';
            case 'membership':
                return 'fas fa-user-tag text-primary';
            default:
                return 'fas fa-bell text-muted';
        }
    }

    /**
     * Format time ago string from timestamp
     * @param {string} timestamp ISO timestamp
     * @returns {string} Time ago string
     */
    formatTimeAgo(timestamp) {
        const date = new Date(timestamp);
        const now = new Date();
        const seconds = Math.floor((now - date) / 1000);
        
        if (seconds < 60) {
            return `${seconds} sec${seconds !== 1 ? 's' : ''} ago`;
        }
        
        const minutes = Math.floor(seconds / 60);
        if (minutes < 60) {
            return `${minutes} min${minutes !== 1 ? 's' : ''} ago`;
        }
        
        const hours = Math.floor(minutes / 60);
        if (hours < 24) {
            return `${hours} hour${hours !== 1 ? 's' : ''} ago`;
        }
        
        const days = Math.floor(hours / 24);
        if (days < 7) {
            return `${days} day${days !== 1 ? 's' : ''} ago`;
        }
        
        return date.toLocaleDateString();
    }

    /**
     * Play notification sound
     */
    playNotificationSound() {
        if (this.soundEnabled) {
            this.notificationSound.currentTime = 0;
            this.notificationSound.play().catch(error => {
                console.error('Error playing notification sound:', error);
            });
        }
    }

    /**
     * Request browser notification permission
     */
    requestNotificationPermission() {
        if ('Notification' in window) {
            if (Notification.permission !== 'granted' && Notification.permission !== 'denied') {
                Notification.requestPermission();
            }
        }
    }

    /**
     * Show browser notification
     * @param {Object} notification Notification object
     */
    showBrowserNotification(notification) {
        if ('Notification' in window && Notification.permission === 'granted' && this.browserNotificationsEnabled) {
            const title = notification.title;
            const options = {
                body: notification.message,
                icon: 'dist/img/logo.png',
                tag: `notification-${notification.id}`
            };
            
            const browserNotification = new Notification(title, options);
            
            // Handle click on the notification
            browserNotification.onclick = () => {
                window.focus();
                this.markAsRead(notification.id);
                browserNotification.close();
            };
            
            // Auto close after 5 seconds
            setTimeout(() => {
                browserNotification.close();
            }, 5000);
        }
    }

    /**
     * Get authentication token
     * @returns {string} Authentication token
     */
    getAuthToken() {
        // In a real application, you would get this from a secure source
        // For demo purposes, we'll use a simple hash of the user ID
        return `token_${this.userId}_${this.userType}`;
    }

    /**
     * Toggle sound notifications
     * @param {boolean} enabled Whether sound is enabled
     */
    toggleSound(enabled) {
        this.soundEnabled = enabled;
        // Save preference to server
        $.ajax({
            url: 'api/notifications/settings.php',
            method: 'POST',
            data: {
                sound_notifications: enabled ? 1 : 0
            }
        });
    }

    /**
     * Toggle browser notifications
     * @param {boolean} enabled Whether browser notifications are enabled
     */
    toggleBrowserNotifications(enabled) {
        this.browserNotificationsEnabled = enabled;
        
        if (enabled && Notification.permission !== 'granted') {
            this.requestNotificationPermission();
        }
        
        // Save preference to server
        $.ajax({
            url: 'api/notifications/settings.php',
            method: 'POST',
            data: {
                browser_notifications: enabled ? 1 : 0
            }
        });
    }
}

// Initialize notification system
const notificationSystem = new NotificationSystem();

// This will be called from the page that includes this script
function initNotificationSystem(config) {
    notificationSystem.init(config);
}
