/**
 * Service intelligent pour monitoring serveur via Server-Sent Events
 * Avec fallback polling et reconnexion automatique
 */

import { API_CONFIG } from '../config/api';

export interface ServerStatusEvent {
    status: 'UP' | 'DOWN' | 'MAINTENANCE';
    timestamp: string;
    message: string;
    system?: {
        version: string;
        uptimeSeconds: number;
        activeConnections: number;
    };
}

export interface ServerStatusListener {
    (isOnline: boolean, event?: ServerStatusEvent): void;
}

export class ServerStatusService {
    private eventSource: EventSource | null = null;
    private listeners: ServerStatusListener[] = [];
    private isOnline: boolean = true;
    private reconnectAttempts: number = 0;
    private maxReconnectAttempts: number = 5;
    private reconnectDelay: number = 1000;
    private fallbackPolling: boolean = false;
    private fallbackInterval: NodeJS.Timeout | null = null;
    private lastEventTime: number = Date.now();
    private heartbeatTimeout: NodeJS.Timeout | null = null;

    constructor() {
        this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
        
        // Vérifier si on est côté client (évite les erreurs SSR)
        if (typeof window !== 'undefined' && typeof document !== 'undefined') {
            document.addEventListener('visibilitychange', this.handleVisibilityChange);
        }
    }

    /**
     * Démarrer le monitoring serveur
     */
    public start(): void {
        console.log('🚀 Démarrage monitoring serveur SSE');
        this.initSSE();
    }

    /**
     * Arrêter le monitoring
     */
    public stop(): void {
        console.log('🛑 Arrêt monitoring serveur');
        this.cleanup();
        
        // Vérifier si on est côté client avant de supprimer l'event listener
        if (typeof window !== 'undefined' && typeof document !== 'undefined') {
            document.removeEventListener('visibilitychange', this.handleVisibilityChange);
        }
    }

    /**
     * S'abonner aux changements de statut
     */
    public onStatusChange(listener: ServerStatusListener): () => void {
        this.listeners.push(listener);
        
        // Retourner une fonction de désabonnement
        return () => {
            const index = this.listeners.indexOf(listener);
            if (index > -1) {
                this.listeners.splice(index, 1);
            }
        };
    }

    /**
     * Obtenir le statut actuel
     */
    public getCurrentStatus(): boolean {
        return this.isOnline;
    }

    /**
     * Initialiser Server-Sent Events
     */
    private initSSE(): void {
        try {
            // Retirer /api/v1 de l'URL de base pour l'endpoint SSE
            const baseUrl = API_CONFIG.baseURL.replace('/api/v1', '');
            const sseUrl = `${baseUrl}/api/server-status/stream`;
            console.log('📡 Connexion SSE:', sseUrl);
            
            this.eventSource = new EventSource(sseUrl);
            
            this.eventSource.onopen = (event) => {
                console.log('✅ SSE connecté avec succès');
                this.reconnectAttempts = 0;
                this.fallbackPolling = false;
                this.stopFallbackPolling();
                this.updateStatus(true);
                this.resetHeartbeatTimeout();
            };

            this.eventSource.onmessage = (event) => {
                try {
                    const statusEvent: ServerStatusEvent = JSON.parse(event.data);
                    console.log('📊 SSE reçu:', statusEvent);
                    
                    this.lastEventTime = Date.now();
                    this.updateStatus(statusEvent.status === 'UP', statusEvent);
                    this.resetHeartbeatTimeout();
                } catch (error) {
                    console.error('❌ Erreur parsing SSE:', error);
                }
            };

            this.eventSource.onerror = (event) => {
                console.warn('⚠️ Erreur SSE, tentative de reconnexion...');
                this.handleSSEError();
            };

        } catch (error) {
            console.error('❌ Impossible d\'initialiser SSE:', error);
            this.startFallbackPolling();
        }
    }

    /**
     * Gérer les erreurs SSE et reconnexion
     */
    private handleSSEError(): void {
        this.updateStatus(false);
        
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.reconnectAttempts++;
            const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1); // Backoff exponentiel
            
            console.log(`🔄 Reconnexion SSE dans ${delay}ms (tentative ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
            
            setTimeout(() => {
                this.cleanup();
                this.initSSE();
            }, delay);
        } else {
            console.warn('❌ Échec reconnexion SSE, passage en mode polling');
            this.startFallbackPolling();
        }
    }

    /**
     * Démarrer le polling de secours
     */
    private startFallbackPolling(): void {
        if (this.fallbackPolling) return;
        
        console.log('🔄 Démarrage polling de secours');
        this.fallbackPolling = true;
        
        const poll = async () => {
            try {
                const controller = new AbortController();
                const timeoutId = setTimeout(() => controller.abort(), 5000);
                
                // Retirer /api/v1 pour l'endpoint de fallback aussi
                const baseUrl = API_CONFIG.baseURL.replace('/api/v1', '');
                const response = await fetch(`${baseUrl}/api/server-status/current`, {
                    signal: controller.signal,
                    headers: { 'Accept': 'application/json' }
                });
                
                clearTimeout(timeoutId);
                
                if (response.ok) {
                    const statusEvent: ServerStatusEvent = await response.json();
                    this.updateStatus(statusEvent.status === 'UP', statusEvent);
                    
                    // Essayer de rétablir SSE si le serveur est de nouveau UP
                    if (statusEvent.status === 'UP' && this.reconnectAttempts >= this.maxReconnectAttempts) {
                        console.log('🔄 Serveur récupéré, tentative de rétablissement SSE');
                        this.stopFallbackPolling();
                        this.reconnectAttempts = 0;
                        setTimeout(() => this.initSSE(), 2000);
                    }
                } else {
                    this.updateStatus(false);
                }
            } catch (error) {
                console.warn('⚠️ Erreur polling de secours:', error);
                this.updateStatus(false);
            }
        };
        
        // Poll immédiat puis toutes les 10 secondes
        poll();
        this.fallbackInterval = setInterval(poll, 10000);
    }

    /**
     * Arrêter le polling de secours
     */
    private stopFallbackPolling(): void {
        if (this.fallbackInterval) {
            clearInterval(this.fallbackInterval);
            this.fallbackInterval = null;
        }
        this.fallbackPolling = false;
    }

    /**
     * Timeout de heartbeat pour détecter les connexions perdues
     */
    private resetHeartbeatTimeout(): void {
        if (this.heartbeatTimeout) {
            clearTimeout(this.heartbeatTimeout);
        }
        
        // Si pas de message pendant 45 secondes (heartbeat = 30s), considérer comme déconnecté
        this.heartbeatTimeout = setTimeout(() => {
            console.warn('💔 Pas de heartbeat SSE, connexion probablement perdue');
            this.handleSSEError();
        }, 45000);
    }

    /**
     * Gérer la visibilité de l'onglet
     */
    private handleVisibilityChange(): void {
        // Vérifier si on est côté client
        if (typeof document === 'undefined') return;
        
        if (!document.hidden) {
            console.log('👁️ Onglet redevenu visible, vérification connexion SSE');
            // Vérifier si la connexion SSE est toujours active
            if (this.eventSource && this.eventSource.readyState === EventSource.CLOSED) {
                console.log('🔄 SSE fermé, reconnexion...');
                this.reconnectAttempts = 0;
                this.initSSE();
            }
        }
    }

    /**
     * Mettre à jour le statut et notifier les listeners
     */
    private updateStatus(isOnline: boolean, event?: ServerStatusEvent): void {
        const wasOnline = this.isOnline;
        this.isOnline = isOnline;
        
        if (wasOnline !== isOnline) {
            console.log(`🔄 Statut serveur changé: ${isOnline ? 'ON' : 'OFF'}LINE`);
        }
        
        // Notifier tous les listeners
        this.listeners.forEach(listener => {
            try {
                listener(isOnline, event);
            } catch (error) {
                console.error('❌ Erreur dans listener status:', error);
            }
        });
    }

    /**
     * Nettoyer les ressources
     */
    private cleanup(): void {
        if (this.eventSource) {
            this.eventSource.close();
            this.eventSource = null;
        }
        
        this.stopFallbackPolling();
        
        if (this.heartbeatTimeout) {
            clearTimeout(this.heartbeatTimeout);
            this.heartbeatTimeout = null;
        }
    }
}

// Instance singleton avec initialisation paresseuse
let _serverStatusService: ServerStatusService | null = null;

export const getServerStatusService = (): ServerStatusService => {
    if (!_serverStatusService && typeof window !== 'undefined') {
        _serverStatusService = new ServerStatusService();
    }
    return _serverStatusService!;
};

// Pour la compatibilité avec l'ancien code
export const serverStatusService = typeof window !== 'undefined' ? getServerStatusService() : null;