// Real-time notification system for competition events

class NotificationManager {
    constructor(eventId, userId = 'anonymous') {
        this.eventId = eventId;
        this.userId = userId;
        this.latestId = 0;
        this.pollingInterval = null;
        this.pollingRate = 3000; // 3 seconds
        this.toastContainer = null;
        this.isActive = true;
        this.notifications = [];
        this.connectionStatus = 'connecting'; // 'connected', 'disconnected', 'connecting'
        this.retryCount = 0;
        this.maxRetries = 5;
        this.apiAvailable = false;
        this.localMode = false; // If true, only use local notifications
        this.categoryFilters = new Set(); // Set of categories to show, empty = show all
        this.categoryColors = {
            'general': 'info',
            'competition': 'primary',
            'participant': 'success',
            'judge': 'warning',
            'system': 'secondary',
            'heat': 'danger',
            'scoring': 'info',
            'technical': 'dark'
        };
        
        // Determine API path based on current location
        this.apiPath = this.getApiPath();
        
        this.init();
    }
    
    // Helper method to get clean numeric user ID
    getCleanUserId() {
        // First try to get from global PHP session variables if available
        if (typeof window.userSession !== 'undefined' && window.userSession.user_id) {
            return window.userSession.user_id;
        }
        
        // Always extract numeric user ID from role-based ID (e.g., "judge_1" -> "1")
        let cleanUserId = this.userId;
        
        // Handle role-based IDs like "judge_1", "participant_2", "admin_3"
        if (typeof cleanUserId === 'string' && cleanUserId.includes('_')) {
            const parts = cleanUserId.split('_');
            const numericPart = parts[parts.length - 1]; // Get last part
            if (!isNaN(numericPart) && numericPart.trim() !== '') {
                cleanUserId = numericPart;
            }
        }
        
        // Ensure we return a string representation of the number
        return cleanUserId.toString();
    }
    
    getApiPath() {
        const currentPath = window.location.pathname;
        if (currentPath.includes('/admin/')) {
            return '../api/notification_api.php';
        } else if (currentPath.includes('/judge/')) {
            return '../api/notification_api.php';
        } else {
            return 'api/notification_api.php';
        }
    }
    
    init() {
        this.createToastContainer();
        
        // Test API availability first
        this.testConnection().then(available => {
            if (available) {
                this.apiAvailable = true;
                this.startPolling();
            } else {
                console.warn('Notification API not available, using local mode only');
                this.localMode = true;
                this.connectionStatus = 'local';
                this.updateConnectionStatus();
            }
        });
        
        // Handle page visibility change
        document.addEventListener('visibilitychange', () => {
            if (document.hidden) {
                this.pausePolling();
            } else {
                this.resumePolling();
            }
        });
        
        // Handle before unload
        window.addEventListener('beforeunload', () => {
            this.stopPolling();
        });
    }
    
    createToastContainer() {
        // Remove existing container if any
        const existing = document.querySelector('.notification-toast-container');
        if (existing) {
            existing.remove();
        }
        
        this.toastContainer = document.createElement('div');
        this.toastContainer.className = 'notification-toast-container position-fixed top-0 end-0 p-3';
        this.toastContainer.style.zIndex = '9999';
        this.toastContainer.style.maxWidth = '400px';
        document.body.appendChild(this.toastContainer);
    }
    
    async sendNotification(type, title, message = '', data = {}, category = 'general') {
        // If in local mode, just show local toast
        if (this.localMode || !this.apiAvailable) {
            this.showLocalToast(type, title, message, category);
            return { success: true, local: true };
        }
        
        try {
            const cleanUserId = this.getCleanUserId();
            console.log('NotificationManager Debug:', {
                original_userId: this.userId,
                clean_userId: cleanUserId,
                session_available: typeof window.userSession !== 'undefined',
                session_user_id: window.userSession?.user_id
            });
            
            const formData = new FormData();
            formData.append('action', 'send_notification');
            formData.append('event_id', this.eventId);
            formData.append('type', type);
            formData.append('title', title);
            formData.append('message', message);
            formData.append('user_id', cleanUserId);
            formData.append('data', JSON.stringify(data));
            formData.append('category', category);
            
            const response = await fetch(this.apiPath, {
                method: 'POST',
                body: formData
            });
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            // Check if response is actually JSON
            const contentType = response.headers.get('content-type');
            if (!contentType || !contentType.includes('application/json')) {
                const text = await response.text();
                console.error('Expected JSON but received:', text.substring(0, 200));
                throw new Error('Server returned non-JSON response. Switching to local mode.');
            }
            
            const result = await response.json();
            
            if (!result.success) {
                throw new Error(result.error || 'Failed to send notification');
            }
            
            return result;
            
        } catch (error) {
            console.error('Error sending notification:', error);
            // Switch to local mode if API fails
            this.localMode = true;
            this.apiAvailable = false;
            this.updateConnectionStatus();
            
            // Show a fallback local toast
            this.showLocalToast(type, title, message + ' (Local mode - API unavailable)', category);
            return { success: true, local: true, error: error.message };
        }
    }
    
    async pollNotifications() {
        if (!this.isActive || this.localMode || !this.apiAvailable) return;
        
        try {
            const response = await fetch(
                `${this.apiPath}?action=get_notifications&event_id=${this.eventId}&since=${this.latestId}&limit=20&user_id=${this.getCleanUserId()}`
            );
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            // Check if response is actually JSON
            const contentType = response.headers.get('content-type');
            if (!contentType || !contentType.includes('application/json')) {
                const text = await response.text();
                console.error('Expected JSON but received:', text.substring(0, 200));
                throw new Error('Server returned non-JSON response. Switching to local mode.');
            }
            
            const data = await response.json();
            
            if (data.success && data.notifications.length > 0) {
                data.notifications.forEach(notification => {
                    // Check if this notification should be shown based on category filters
                    if (this.shouldShowNotification(notification)) {
                        this.showToast(notification);
                    }
                });
                
                this.latestId = data.latest_id;
                this.notifications.push(...data.notifications);
            }
            
            // Connection successful
            if (this.connectionStatus !== 'connected') {
                this.connectionStatus = 'connected';
                this.retryCount = 0;
                this.updateConnectionStatus();
            }
            
        } catch (error) {
            console.error('Error polling notifications:', error);
            
            this.retryCount++;
            
            // If too many failures, switch to local mode
            if (this.retryCount > this.maxRetries) {
                console.warn('Too many API failures, switching to local mode');
                this.localMode = true;
                this.apiAvailable = false;
                this.connectionStatus = 'local';
                this.updateConnectionStatus();
                return;
            }
            
            this.connectionStatus = 'disconnected';
            this.updateConnectionStatus();
            
            // Exponential backoff for retries
            const retryDelay = Math.min(1000 * Math.pow(2, this.retryCount), 30000);
            setTimeout(() => {
                if (this.isActive && !this.localMode) {
                    this.pollNotifications();
                }
            }, retryDelay);
        }
    }
    
    // Check if notification should be shown based on category filters
    shouldShowNotification(notification) {
        // If no filters set, show all notifications
        if (this.categoryFilters.size === 0) {
            return true;
        }
        
        // Check if notification category is in the filter set
        return this.categoryFilters.has(notification.category || 'general');
    }
    
    // Set category filters (array of category names to show)
    setCategoryFilters(categories = []) {
        this.categoryFilters.clear();
        categories.forEach(category => this.categoryFilters.add(category));
    }
    
    // Add a category to filters
    addCategoryFilter(category) {
        this.categoryFilters.add(category);
    }
    
    // Remove a category from filters
    removeCategoryFilter(category) {
        this.categoryFilters.delete(category);
    }
    
    // Clear all category filters (show all notifications)
    clearCategoryFilters() {
        this.categoryFilters.clear();
    }
    
    updateConnectionStatus() {
        // Update any UI indicators for connection status
        const indicator = document.getElementById('liveStatusIndicator');
        if (indicator) {
            if (this.connectionStatus === 'connected') {
                indicator.innerHTML = '<i class="fas fa-circle me-1"></i>LIVE';
                indicator.className = 'badge bg-success live-pulse';
            } else if (this.connectionStatus === 'disconnected') {
                indicator.innerHTML = '<i class="fas fa-exclamation-triangle me-1"></i>DISCONNECTED';
                indicator.className = 'badge bg-danger';
            } else if (this.connectionStatus === 'local') {
                indicator.innerHTML = '<i class="fas fa-desktop me-1"></i>LOCAL';
                indicator.className = 'badge bg-warning';
            }
        }
    }
    
    showToast(notification) {
        const toast = this.createToastElement(notification);
        this.toastContainer.appendChild(toast);
        
        // Animate in
        setTimeout(() => {
            toast.classList.add('show');
        }, 100);
        
        // Auto-remove after duration based on type
        const duration = this.getToastDuration(notification.type);
        setTimeout(() => {
            this.removeToast(toast);
        }, duration);
        
        // Add sound notification for important messages
        this.playNotificationSound(notification.type);
    }
    
    // Fallback method for local toasts when API is unavailable
    showLocalToast(type, title, message = '', category = 'general') {
        const localNotification = {
            id: 'local_' + Date.now(),
            type: type,
            title: title,
            message: message,
            category: category,
            created_at: new Date().toISOString(),
            user_id: this.userId
        };
        
        this.showToast(localNotification);
    }
    
    createToastElement(notification) {
        const toast = document.createElement('div');
        
        // Use category-specific color if available, otherwise use notification type
        const colorType = this.categoryColors[notification.category] || notification.type;
        
        toast.className = `toast notification-toast bg-${colorType} text-white border-0 mb-2`;
        toast.setAttribute('role', 'alert');
        toast.setAttribute('aria-live', 'assertive');
        toast.setAttribute('aria-atomic', 'true');
        toast.setAttribute('data-notification-id', notification.id);
        toast.setAttribute('data-category', notification.category || 'general');
        
        const iconMap = {
            'success': 'fa-check-circle',
            'danger': 'fa-exclamation-circle',
            'warning': 'fa-exclamation-triangle',
            'info': 'fa-info-circle'
        };
        
        const time = new Date(notification.created_at).toLocaleTimeString();
        const categoryBadge = notification.category ? `<span class="badge bg-light text-dark opacity-75 me-2">${notification.category}</span>` : '';
        
        toast.innerHTML = `
            <div class="toast-header bg-transparent text-white border-0">
                <i class="fas ${iconMap[notification.type]} me-2"></i>
                <strong class="me-auto">${this.escapeHtml(notification.title)}</strong>
                ${categoryBadge}
                <small class="opacity-75">${time}</small>
                <button type="button" class="btn-close btn-close-white ms-2" aria-label="Close"></button>
            </div>
            ${notification.message ? `
                <div class="toast-body border-top border-light border-opacity-25">
                    ${this.escapeHtml(notification.message)}
                </div>
            ` : ''}
        `;
        
        // Add close button functionality
        const closeBtn = toast.querySelector('.btn-close');
        closeBtn.addEventListener('click', () => {
            this.removeToast(toast);
            this.markAsRead(notification.id);
        });
        
        return toast;
    }
    
    removeToast(toast) {
        toast.classList.remove('show');
        toast.style.opacity = '0';
        toast.style.transform = 'translateX(100%)';
        
        setTimeout(() => {
            if (toast.parentNode) {
                toast.parentNode.removeChild(toast);
            }
        }, 300);
    }
    
    getToastDuration(type) {
        const durations = {
            'danger': 30000,   // 30 seconds for errors
            'warning': 20000,  // 20 seconds for warnings
            'success': 15000,  // 15 seconds for success
            'info': 10000      // 10 seconds for info
        };
        
        return durations[type] || 15000;
    }
    
    playNotificationSound(type) {
        // Only play sound for important notifications
        if (type === 'danger' || type === 'warning') {
            try {
                // Create a simple beep sound
                const audioContext = new (window.AudioContext || window.webkitAudioContext)();
                const oscillator = audioContext.createOscillator();
                const gainNode = audioContext.createGain();
                
                oscillator.connect(gainNode);
                gainNode.connect(audioContext.destination);
                
                oscillator.frequency.value = type === 'danger' ? 800 : 600;
                oscillator.type = 'sine';
                
                gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
                gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
                
                oscillator.start(audioContext.currentTime);
                oscillator.stop(audioContext.currentTime + 0.3);
            } catch (error) {
                // Ignore audio errors
            }
        }
    }
    
    async markAsRead(notificationId) {
        try {
            const cleanUserId = this.getCleanUserId();
            console.log('MarkAsRead Debug:', {
                notification_id: notificationId,
                original_userId: this.userId,
                clean_userId: cleanUserId,
                session_available: typeof window.userSession !== 'undefined',
                session_user_id: window.userSession?.user_id
            });
            
            const formData = new FormData();
            formData.append('action', 'dismiss_notification');
            formData.append('notification_id', notificationId);
            formData.append('user_id', cleanUserId);
            
            const response = await fetch(this.apiPath, {
                method: 'POST',
                body: formData
            });
            
            const result = await response.json();
            console.log('MarkAsRead Response:', result);
            
        } catch (error) {
            console.error('Error marking notification as read:', error);
        }
    }
    
    startPolling() {
        this.stopPolling(); // Clear any existing interval
        this.isActive = true;
        
        // Initial poll
        this.pollNotifications();
        
        // Set up regular polling
        this.pollingInterval = setInterval(() => {
            this.pollNotifications();
        }, this.pollingRate);
    }
    
    stopPolling() {
        this.isActive = false;
        if (this.pollingInterval) {
            clearInterval(this.pollingInterval);
            this.pollingInterval = null;
        }
    }
    
    pausePolling() {
        this.isActive = false;
    }
    
    resumePolling() {
        this.isActive = true;
    }
    
    // Helper method to escape HTML
    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
    
    // Public methods for sending specific competition notifications
    async notifyParticipantOnStart(bibNumber, participantName) {
        return this.sendNotification('info', 
            `🏁 Participant #${bibNumber} On Start`, 
            `${participantName} is now on the starting line`,
            { type: 'participant_on_start', bib: bibNumber, name: participantName },
            'participant'
        );
    }
    
    // Method to test API connectivity
    async testConnection() {
        try {
            const response = await fetch(
                `${this.apiPath}?action=get_notifications&event_id=${this.eventId}&since=0&limit=1`
            );
            
            if (!response.ok) {
                throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            
            const contentType = response.headers.get('content-type');
            if (!contentType || !contentType.includes('application/json')) {
                throw new Error('API not returning JSON');
            }
            
            const data = await response.json();
            return data.success;
            
        } catch (error) {
            console.error('Connection test failed:', error);
            return false;
        }
    }
    
    async notifyParticipantCompleted(bibNumber, participantName) {
        return this.sendNotification('success', 
            `🏆 Participant #${bibNumber} Completed`, 
            `${participantName} has finished their run`,
            { type: 'participant_completed', bib: bibNumber, name: participantName },
            'participant'
        );
    }
    
    async notifyParticipantStarted(bibNumber, participantName) {
        return this.sendNotification('warning', 
            `🚀 Participant #${bibNumber} Started`, 
            `${participantName} has begun their performance`,
            { type: 'participant_started', bib: bibNumber, name: participantName },
            'participant'
        );
    }
    
    async notifyNextParticipant(bibNumber, participantName) {
        return this.sendNotification('info', 
            `⏭️ Next Participant Ready`, 
            `#${bibNumber} ${participantName} is now next in queue`,
            { type: 'next_participant', bib: bibNumber, name: participantName },
            'participant'
        );
    }
    
    async notifyHeatActivated(heatNumber, runNumber) {
        return this.sendNotification('success', 
            `🔥 Heat ${heatNumber} Activated`, 
            `Run ${runNumber} is now active and competition is live`,
            { type: 'heat_activated', heat: heatNumber, run: runNumber },
            'heat'
        );
    }
    
    async notifyHeatDeactivated(heatNumber) {
        return this.sendNotification('warning', 
            `⏸️ Heat ${heatNumber} Deactivated`, 
            `Competition has been paused or stopped`,
            { type: 'heat_deactivated', heat: heatNumber },
            'heat'
        );
    }
    
    async notifyEmergencyStop() {
        return this.sendNotification('danger', 
            `🚨 EMERGENCY STOP`, 
            `Competition has been immediately stopped - all activities halted`,
            { type: 'emergency_stop' },
            'system'
        );
    }
    
    async notifyAutoAdvance(fromBib, toBib, toName) {
        return this.sendNotification('info', 
            `⚡ Auto-Advanced`, 
            `Moved from #${fromBib} to #${toBib} ${toName}`,
            { type: 'auto_advance', from_bib: fromBib, to_bib: toBib, to_name: toName },
            'competition'
        );
    }
    
    // Additional category-specific notification methods
    async notifyJudgeAction(action, details) {
        return this.sendNotification('info', 
            `👨‍💼 Judge Action: ${action}`, 
            details,
            { type: 'judge_action', action: action },
            'judge'
        );
    }
    
    async notifyScoreUpdate(participantBib, score, judge) {
        return this.sendNotification('success', 
            `📊 Score Updated`, 
            `#${participantBib} - Score: ${score} (Judge: ${judge})`,
            { type: 'score_update', bib: participantBib, score: score, judge: judge },
            'scoring'
        );
    }
    
    async notifySystemStatus(status, message) {
        return this.sendNotification('warning', 
            `⚙️ System Status: ${status}`, 
            message,
            { type: 'system_status', status: status },
            'technical'
        );
    }
    
    async notifyGeneralAnnouncement(title, message) {
        return this.sendNotification('info', 
            title, 
            message,
            { type: 'general_announcement' },
            'general'
        );
    }
    
    // Clear all notifications for this event
    async clearAllNotifications() {
        try {
            const formData = new FormData();
            formData.append('action', 'clear_all');
            formData.append('event_id', this.eventId);
            
            const response = await fetch(this.apiPath, {
                method: 'POST',
                body: formData
            });
            
            const result = await response.json();
            
            if (response.ok) {
                // Clear local toast container
                this.toastContainer.innerHTML = '';
                this.notifications = [];
                this.latestId = 0;
            }
            
            return result;
        } catch (error) {
            console.error('Error clearing notifications:', error);
            throw error;
        }
    }
}

// Export for use in other scripts
window.NotificationManager = NotificationManager;
