/**
 * Native WebSocket Client Wrapper
 * Provides Socket.IO-like interface using native WebSocket API
 * 
 * This wrapper maintains compatibility with existing Socket.IO-style
 * event handlers while using the modern WebSocket API underneath.
 */

class WebSocketClient {
    constructor(url = null) {
        this.ws = null;
        this.url = url || this.getWebSocketUrl();
        this.eventHandlers = new Map();
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectDelay = 1000;
        this.isConnected = false;
        this.rooms = new Set();
        this.messageQueue = [];
        this.autoReconnect = true;
    }

    /**
     * Get WebSocket URL based on current page URL
     */
    getWebSocketUrl() {
        const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
        const host = window.location.host;
        return `${protocol}//${host}/ws/connect`;
    }

    /**
     * Connect to WebSocket server
     */
    connect() {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            console.log('WebSocket already connected');
            return;
        }

        try {
            this.ws = new WebSocket(this.url);

            this.ws.onopen = () => {
                console.log('WebSocket connected');
                this.isConnected = true;
                this.reconnectAttempts = 0;
                
                // Emit connect event
                this.emit('connect');
                
                // Rejoin rooms
                this.rejoinRooms();
                
                // Process queued messages
                this.processMessageQueue();
            };

            this.ws.onmessage = (event) => {
                this.handleMessage(event.data);
            };

            this.ws.onerror = (error) => {
                console.error('WebSocket error:', error);
                this.emit('error', { error: 'WebSocket connection error' });
            };

            this.ws.onclose = (event) => {
                console.log('WebSocket disconnected', event.code, event.reason);
                this.isConnected = false;
                this.emit('disconnect', { code: event.code, reason: event.reason });
                
                // Attempt reconnection
                if (this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
                    this.reconnectAttempts++;
                    const delay = this.reconnectDelay * this.reconnectAttempts;
                    console.log(`Attempting reconnection in ${delay}ms (attempt ${this.reconnectAttempts})`);
                    setTimeout(() => this.connect(), delay);
                }
            };
        } catch (error) {
            console.error('Failed to create WebSocket connection:', error);
            this.emit('error', { error: 'Failed to connect' });
        }
    }

    /**
     * Disconnect from WebSocket server
     */
    disconnect() {
        this.autoReconnect = false;
        if (this.ws) {
            this.ws.close(1000, 'Client disconnected');
        }
    }

    /**
     * Handle incoming WebSocket message
     */
    handleMessage(data) {
        try {
            const message = JSON.parse(data);
            const { type, data: payload, timestamp } = message;

            console.log(`WebSocket message: type=${type}`, payload);

            // Emit event with payload
            if (type) {
                this.emit(type, payload || {});
            }
        } catch (error) {
            console.error('Failed to parse WebSocket message:', error, data);
        }
    }

    /**
     * Register event handler (Socket.IO-style)
     */
    on(event, handler) {
        if (!this.eventHandlers.has(event)) {
            this.eventHandlers.set(event, []);
        }
        this.eventHandlers.get(event).push(handler);
    }

    /**
     * Remove event handler
     */
    off(event, handler) {
        if (!this.eventHandlers.has(event)) {
            return;
        }
        
        const handlers = this.eventHandlers.get(event);
        const index = handlers.indexOf(handler);
        if (index !== -1) {
            handlers.splice(index, 1);
        }
    }

    /**
     * Emit event to registered handlers
     */
    emit(event, data = null) {
        if (!this.eventHandlers.has(event)) {
            return;
        }

        const handlers = this.eventHandlers.get(event);
        handlers.forEach(handler => {
            try {
                if (data !== null) {
                    handler(data);
                } else {
                    handler();
                }
            } catch (error) {
                console.error(`Error in event handler for ${event}:`, error);
            }
        });
    }

    /**
     * Send message to server
     */
    send(action, data = {}) {
        const message = JSON.stringify({
            action,
            data
        });

        if (this.isConnected && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(message);
        } else {
            console.warn('WebSocket not connected, queueing message');
            this.messageQueue.push(message);
        }
    }

    /**
     * Join a room (subscribe to topic)
     */
    join(room) {
        this.rooms.add(room);
        if (this.isConnected) {
            this.send('join', { room });
        }
    }

    /**
     * Leave a room (unsubscribe from topic)
     */
    leave(room) {
        this.rooms.delete(room);
        if (this.isConnected) {
            this.send('leave', { room });
        }
    }

    /**
     * Rejoin all rooms after reconnection
     */
    rejoinRooms() {
        this.rooms.forEach(room => {
            this.send('join', { room });
        });
    }

    /**
     * Process queued messages after connection
     */
    processMessageQueue() {
        while (this.messageQueue.length > 0 && this.isConnected) {
            const message = this.messageQueue.shift();
            this.ws.send(message);
        }
    }

    /**
     * Check if connected
     */
    connected() {
        return this.isConnected && this.ws && this.ws.readyState === WebSocket.OPEN;
    }
}

/**
 * Create global io() function for Socket.IO compatibility
 */
function io(url = null) {
    const client = new WebSocketClient(url);
    client.connect();
    return client;
}
