// WebSocket Manager for Real-time Updates

class WebSocketManager {
    constructor() {
        this.ws = null;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectDelay = 1000;
        this.isConnected = false;
        this.subscribers = new Map();
        this.init();
    }

    init() {
        this.connect();
        this.setupStatusIndicator();
        this.setupAutoReconnect();
    }

    connect() {
        try {
            // Determine WebSocket URL
            const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
            const host = window.location.host;
            const wsUrl = `${protocol}//${host}/ws`;
            
            this.ws = new WebSocket(wsUrl);
            
            this.ws.onopen = () => this.onOpen();
            this.ws.onclose = () => this.onClose();
            this.ws.onerror = (error) => this.onError(error);
            this.ws.onmessage = (event) => this.onMessage(event);
            
        } catch (error) {
            console.error('WebSocket connection error:', error);
            this.scheduleReconnect();
        }
    }

    onOpen() {
        console.log('WebSocket connected');
        this.isConnected = true;
        this.reconnectAttempts = 0;
        this.updateStatus('connected');
        
        // Notify subscribers
        this.notify('connection', { status: 'connected' });
        
        // Send authentication if needed
        if (window.authManager && window.authManager.token) {
            this.send({
                type: 'auth',
                token: window.authManager.token
            });
        }
        
        // Subscribe to default channels
        this.send({
            type: 'subscribe',
            channels: ['requests', 'metrics', 'logs']
        });
    }

    onClose() {
        console.log('WebSocket disconnected');
        this.isConnected = false;
        this.updateStatus('disconnected');
        
        // Notify subscribers
        this.notify('connection', { status: 'disconnected' });
        
        // Schedule reconnection
        this.scheduleReconnect();
    }

    onError(error) {
        console.error('WebSocket error:', error);
        this.updateStatus('error');
    }

    onMessage(event) {
        try {
            const data = JSON.parse(event.data);
            this.handleMessage(data);
        } catch (error) {
            console.error('Error parsing WebSocket message:', error);
        }
    }

    handleMessage(data) {
        // Handle request events
        if (data.type === 'request') {
            this.notify('requests', data.payload);
        }
        
        // Notify specific channel subscribers
        const channel = data.channel || data.type;
        if (channel && this.subscribers.has(channel)) {
            this.subscribers.get(channel).forEach(callback => {
                try {
                    callback(data.payload);
                } catch (error) {
                    console.error('Error in WebSocket callback:', error);
                }
            });
        }
    }

    handleRequest(request) {
        // Update request counters
        this.updateRequestCounters(request);
        
        // Add to recent requests if on overview page
        if (window.dashboard && window.dashboard.currentPage === 'overview') {
            this.addRecentRequest(request);
        }
        
        // Update monitoring stream if on monitoring page
        if (window.dashboard && window.dashboard.currentPage === 'monitoring') {
            this.addToMonitoringStream(request);
        }
    }

    handleMetric(metric) {
        // Update charts with new metric data
        this.updateCharts(metric);
        
        // Update system metrics display
        this.updateSystemMetrics(metric);
    }

    handleLog(log) {
        // Add to logs table if on logs page
        if (window.dashboard && window.dashboard.currentPage === 'logs') {
            this.addLogEntry(log);
        }
        
        // Add to monitoring logs if on monitoring page
        if (window.dashboard && window.dashboard.currentPage === 'monitoring') {
            this.addToLogStream(log);
        }
    }

    handleSystem(system) {
        // Update system health indicators
        this.updateSystemHealth(system);
    }

    handleError(error) {
        console.error('Server error:', error);
        
        // Show error toast
        if (window.authManager) {
            window.authManager.showToast(error.message || 'Server error', 'error');
        }
    }

    send(data) {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(data));
            return true;
        } else {
            console.warn('WebSocket not connected, message not sent:', data);
            return false;
        }
    }

    subscribe(channel, callback) {
        if (!this.subscribers.has(channel)) {
            this.subscribers.set(channel, new Set());
        }
        this.subscribers.get(channel).add(callback);
        
        // Send subscription to server
        this.send({
            type: 'subscribe',
            channels: [channel]
        });
        
        // Return unsubscribe function
        return () => this.unsubscribe(channel, callback);
    }

    unsubscribe(channel, callback) {
        if (this.subscribers.has(channel)) {
            this.subscribers.get(channel).delete(callback);
            
            // If no more subscribers, unsubscribe from server
            if (this.subscribers.get(channel).size === 0) {
                this.send({
                    type: 'unsubscribe',
                    channels: [channel]
                });
            }
        }
    }

    notify(channel, data) {
        if (this.subscribers.has(channel)) {
            this.subscribers.get(channel).forEach(callback => {
                try {
                    callback(data);
                } catch (error) {
                    console.error('Error in notification callback:', error);
                }
            });
        }
    }

    scheduleReconnect() {
        if (this.reconnectAttempts >= this.maxReconnectAttempts) {
            console.warn('Max reconnection attempts reached');
            return;
        }
        
        this.reconnectAttempts++;
        const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
        
        console.log(`Scheduling reconnection in ${delay}ms (attempt ${this.reconnectAttempts})`);
        
        setTimeout(() => {
            if (!this.isConnected) {
                this.connect();
            }
        }, delay);
    }

    setupAutoReconnect() {
        // Reconnect when browser comes online
        window.addEventListener('online', () => {
            if (!this.isConnected) {
                console.log('Browser online, attempting to reconnect...');
                this.connect();
            }
        });
        
        // Keepalive ping
        setInterval(() => {
            if (this.isConnected) {
                this.send({ type: 'ping' });
            }
        }, 30000);
    }

    setupStatusIndicator() {
        // Status indicator is already in the HTML
        // This function just ensures it's properly styled
    }

    updateStatus(status) {
        const statusElement = document.getElementById('connection-status');
        if (!statusElement) return;
        
        const dot = statusElement.querySelector('.status-dot');
        const text = statusElement.querySelector('.status-text');
        
        if (!dot || !text) return;
        
        // Remove all status classes
        dot.classList.remove('connected', 'disconnected', 'error', 'connecting');
        
        // Add new status class
        dot.classList.add(status);
        
        // Update text
        const statusText = {
            'connected': 'Connected',
            'disconnected': 'Disconnected',
            'connecting': 'Connecting...',
            'error': 'Connection Error'
        };
        
        text.textContent = statusText[status] || status;
    }

    // Helper methods for updating UI
    updateRequestCounters(request) {
        // Update request counters in overview stats
        const requestCountElement = document.querySelector('[data-stat="total-requests"]');
        if (requestCountElement) {
            const currentCount = parseInt(requestCountElement.textContent) || 0;
            requestCountElement.textContent = currentCount + 1;
        }
        
        // Update token counters
        const tokenCountElement = document.querySelector('[data-stat="total-tokens"]');
        if (tokenCountElement && (request.total_tokens || request.tokens)) {
            const currentTokens = parseInt(tokenCountElement.textContent) || 0;
            tokenCountElement.textContent = currentTokens + (request.total_tokens || request.tokens);
        }
    }

    addRecentRequest(request) {
        const tableBody = document.querySelector('#recent-requests tbody');
        if (!tableBody) return;
        
        const row = document.createElement('tr');
        
        // Format time
        const time = new Date(request.timestamp || Date.now()).toLocaleTimeString();
        
        // Format status badge
        const statusClass = request.status === 'success' ? 'success' : 
                          request.status === 'error' ? 'danger' : 'warning';
        const statusIcon = request.status === 'success' ? 'check-circle' :
                          request.status === 'error' ? 'exclamation-circle' : 'exclamation-triangle';
        
        row.innerHTML = `
            <td>${time}</td>
            <td>${request.client_id || 'Unknown'}</td>
            <td>${request.provider || 'Unknown'}</td>
            <td>${request.model || 'Unknown'}</td>
            <td>${(request.total_tokens || request.tokens || 0)}</td>
            <td>
                <span class="status-badge ${statusClass}">
                    <i class="fas fa-${statusIcon}"></i>
                    ${request.status || 'unknown'}
                </span>
            </td>
        `;
        
        // Add to top of table
        tableBody.insertBefore(row, tableBody.firstChild);
        
        // Limit to 50 rows
        const rows = tableBody.querySelectorAll('tr');
        if (rows.length > 50) {
            tableBody.removeChild(rows[rows.length - 1]);
        }
    }

    addToMonitoringStream(request) {
        const streamElement = document.getElementById('request-stream');
        if (!streamElement) return;
        
        const entry = document.createElement('div');
        entry.className = 'stream-entry';
        
        // Format time
        const time = new Date().toLocaleTimeString();
        
        // Determine icon based on status
        let icon = 'question-circle';
        let color = 'var(--text-secondary)';
        
        if (request.status === 'success') {
            icon = 'check-circle';
            color = 'var(--success)';
        } else if (request.status === 'error') {
            icon = 'exclamation-circle';
            color = 'var(--danger)';
        }
        
        entry.innerHTML = `
            <div class="stream-entry-time">${time}</div>
            <div class="stream-entry-icon" style="color: ${color}">
                <i class="fas fa-${icon}"></i>
            </div>
            <div class="stream-entry-content">
                <strong>${request.client_id || 'Unknown'}</strong> → 
                ${request.provider || 'Unknown'} (${request.model || 'Unknown'})
                <div class="stream-entry-details">
                    ${(request.total_tokens || request.tokens || 0)} tokens • ${(request.duration_ms || request.duration || 0)}ms
                </div>
            </div>
        `;
        
        // Add to top of stream
        streamElement.insertBefore(entry, streamElement.firstChild);
        
        // Limit to 20 entries
        const entries = streamElement.querySelectorAll('.stream-entry');
        if (entries.length > 20) {
            streamElement.removeChild(entries[entries.length - 1]);
        }
        
        // Add highlight animation
        entry.classList.add('highlight');
        setTimeout(() => entry.classList.remove('highlight'), 1000);
    }

    updateCharts(metric) {
        // This would update Chart.js charts with new data
        // Implementation depends on specific chart setup
    }

    updateSystemMetrics(metric) {
        const metricsElement = document.getElementById('system-metrics');
        if (!metricsElement) return;
        
        // Update specific metric displays
        // This is a simplified example
    }

    addLogEntry(log) {
        const tableBody = document.querySelector('#logs-table tbody');
        if (!tableBody) return;
        
        const row = document.createElement('tr');
        
        // Format time
        const time = new Date(log.timestamp || Date.now()).toLocaleString();
        
        // Determine log level class
        const levelClass = log.level || 'info';
        
        row.innerHTML = `
            <td>${time}</td>
            <td>
                <span class="status-badge ${levelClass}">
                    ${levelClass.toUpperCase()}
                </span>
            </td>
            <td>${log.source || 'Unknown'}</td>
            <td>${log.message || ''}</td>
        `;
        
        // Add to top of table
        tableBody.insertBefore(row, tableBody.firstChild);
        
        // Limit to 100 rows
        const rows = tableBody.querySelectorAll('tr');
        if (rows.length > 100) {
            tableBody.removeChild(rows[rows.length - 1]);
        }
    }

    addToLogStream(log) {
        const logStreamElement = document.getElementById('system-logs');
        if (!logStreamElement) return;
        
        const entry = document.createElement('div');
        entry.className = `log-entry log-${log.level || 'info'}`;
        
        // Format time
        const time = new Date().toLocaleTimeString();
        
        // Determine icon based on level
        let icon = 'info-circle';
        if (log.level === 'error') icon = 'exclamation-circle';
        if (log.level === 'warn') icon = 'exclamation-triangle';
        if (log.level === 'debug') icon = 'bug';
        
        entry.innerHTML = `
            <div class="log-time">${time}</div>
            <div class="log-level">
                <i class="fas fa-${icon}"></i>
            </div>
            <div class="log-message">${log.message || ''}</div>
        `;
        
        // Add to top of stream
        logStreamElement.insertBefore(entry, logStreamElement.firstChild);
        
        // Limit to 50 entries
        const entries = logStreamElement.querySelectorAll('.log-entry');
        if (entries.length > 50) {
            logStreamElement.removeChild(entries[entries.length - 1]);
        }
    }

    updateSystemHealth(system) {
        const healthElement = document.getElementById('system-health');
        if (!healthElement) return;
        
        // Update system health indicators
        // This is a simplified example
    }

    disconnect() {
        if (this.ws) {
            this.ws.close();
            this.ws = null;
        }
        this.isConnected = false;
        this.updateStatus('disconnected');
    }

    reconnect() {
        this.disconnect();
        this.connect();
    }
}

// Initialize WebSocket manager when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    window.wsManager = new WebSocketManager();
});

// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
    module.exports = WebSocketManager;
}