// Define the runtime configuration interface
interface RuntimeConfig {
  API_URL: string;
}
declare global {
  interface Window {
    runtimeConfig?: RuntimeConfig;
  }
}

class WebSocketService {
    private ws: WebSocket | null = null;
    private messageHandlers: ((message: any) => void)[] = [];
    private errorHandlers: ((error: Event) => void)[] = [];
    private sessionTerminatedHandlers: (() => void)[] = [];
    private currentSessionId: string | null = null;
    private currentClientId: string | null = null;
    private heartbeatInterval: NodeJS.Timeout | null = null;

    connect(sessionId: string, clientId: string) {
        // Prevent multiple connections
        if (this.ws) {
            return;
        }

        this.currentSessionId = sessionId;
        this.currentClientId = clientId;
        // Read the API_URL from the runtime configuration
        const apiUrl = window.runtimeConfig?.API_URL || 'ws://localhost:8000';
        const wsUrl = `${apiUrl.replace(/^http/, 'ws')}/sessions/${sessionId}`;
        this.ws = new WebSocket(wsUrl);

        this.ws.onopen = () => {
            console.log('WebSocket connected');
            // Directly send registration message on open
            this.sendMessage({ type: 'REGISTER_CLIENT' });

            // Start heartbeat to keep connection alive
            this.heartbeatInterval = setInterval(() => {
                if (this.ws && this.ws.readyState === WebSocket.OPEN) {
                    this.ws.send(JSON.stringify({ type: 'PING', clientId: this.currentClientId, sessionId: this.currentSessionId }));
                }
            }, 30000); // Send ping every 30 seconds
        };

        this.ws.onmessage = (event) => {
            try {
                const message = JSON.parse(event.data);
                console.log('WebSocketService: Received and parsed message:', message);
                this.messageHandlers.forEach(handler => handler(message));
            } catch (error) {
                console.error('Error parsing incoming message:', error);
            }
        };

        this.ws.onclose = () => {
            console.log('WebSocket disconnected');
            if (this.heartbeatInterval) {
                clearInterval(this.heartbeatInterval);
                this.heartbeatInterval = null;
            }
            this.sessionTerminatedHandlers.forEach(handler => handler());
            this.ws = null;
            this.currentSessionId = null;
            this.currentClientId = null;
        };

        this.ws.onerror = (event) => {
            console.error('WebSocket error:', event);
            if (this.heartbeatInterval) {
                clearInterval(this.heartbeatInterval);
                this.heartbeatInterval = null;
            }
            this.errorHandlers.forEach(handler => handler(event));
        };




    }

    disconnect() {
        if (this.ws) {
            this.ws.close();
        }
        if (this.heartbeatInterval) {
            clearInterval(this.heartbeatInterval);
            this.heartbeatInterval = null;
        }
    }

    sendMessage(message: any) {
        if (this.ws && this.ws.readyState === WebSocket.OPEN && this.currentClientId && this.currentSessionId) {
            const messageToSend = {
                ...message,
                clientId: this.currentClientId,
                sessionId: this.currentSessionId,
            };
            this.ws.send(JSON.stringify(messageToSend));
        } else {
            // This error can be ignored if it happens during initial connection in StrictMode
            // console.error('WebSocket is not connected or clientId/sessionId is missing.');
        }
    }

    onMessage(handler: (message: any) => void) {
        this.messageHandlers.push(handler);
    }

    removeMessageHandler(handler: (message: any) => void) {
        this.messageHandlers = this.messageHandlers.filter(h => h !== handler);
    }

    onError(handler: (error: Event) => void) {
        this.errorHandlers.push(handler);
    }

    removeErrorHandler(handler: (error: Event) => void) {
        this.errorHandlers = this.errorHandlers.filter(h => h !== handler);
    }

    onSessionTerminated(handler: () => void) {
        this.sessionTerminatedHandlers.push(handler);
    }

    removeSessionTerminatedHandler(handler: () => void) {
        this.sessionTerminatedHandlers = this.sessionTerminatedHandlers.filter(h => h !== handler);
    }
}

export const webSocketService = new WebSocketService();
