class ChatSystem {
    constructor(config) {
        this.config = {
            wsUrl: config.wsUrl || 'ws://localhost:3001',
            apiUrl: config.apiUrl || '/api/chat',
            userType: config.userType,
            userId: config.userId,
            userName: config.userName,
            userAvatar: config.userAvatar,
            autoReconnect: config.autoReconnect !== false,
            reconnectDelay: config.reconnectDelay || 3000,
            maxReconnectAttempts: config.maxReconnectAttempts || 5
        };
        
        this.ws = null;
        this.reconnectAttempts = 0;
        this.isConnected = false;
        this.isAuthenticated = false;
        this.connectionId = null;
        
        // Message tracking
        this.lastMessageId = 0;
        this.typingTimeout = null;
        this.lastTypingSent = 0;
        
        // Heartbeat
        this.heartbeatInterval = null;
        this.lastHeartbeat = null;
        this.heartbeatTimeout = 30000; // 30 seconds
        
        // State
        this.activeConversation = null;
        this.unreadCounts = new Map();
        this.onlineUsers = new Set();
        
        // Initialize
        this.init();
    }
    
    init() {
        this.connectWebSocket();
        this.setupEventListeners();
        
        // Auto authenticate after 500ms if not already authenticated
        setTimeout(() => {
            if (this.isConnected && !this.isAuthenticated) {
                this.authenticate();
            }
        }, 500);
    }
    
    connectWebSocket() {
        try {
            this.ws = new WebSocket(this.config.wsUrl);
            
            this.ws.onopen = () => {
                console.log('WebSocket connected');
                this.isConnected = true;
                this.reconnectAttempts = 0;
                
                // Start heartbeat immediately
                this.startHeartbeat();
                
                // Authenticate
                this.authenticate();
            };
            
            this.ws.onmessage = (event) => {
                this.handleMessage(event.data);
            };
            
            this.ws.onclose = () => {
                console.log('WebSocket disconnected');
                this.isConnected = false;
                this.isAuthenticated = false;
                
                // Clear heartbeat
                if (this.heartbeatInterval) {
                    clearInterval(this.heartbeatInterval);
                    this.heartbeatInterval = null;
                }
                
                if (this.config.autoReconnect && this.reconnectAttempts < this.config.maxReconnectAttempts) {
                    setTimeout(() => {
                        this.reconnectAttempts++;
                        console.log(`Reconnecting... Attempt ${this.reconnectAttempts}`);
                        this.connectWebSocket();
                    }, this.config.reconnectDelay);
                }
            };
            
            this.ws.onerror = (error) => {
                console.error('WebSocket error:', error);
            };
            
        } catch (error) {
            console.error('Failed to connect WebSocket:', error);
        }
    }
    
    authenticate() {
        if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
            console.log('WebSocket not ready for authentication');
            return;
        }
        
        const authData = {
            type: 'auth',
            userType: this.config.userType,
            userId: this.config.userId,
            userName: this.config.userName,
            userAvatar: this.config.userAvatar
        };
        
        console.log('Sending authentication:', authData);
        this.ws.send(JSON.stringify(authData));
    }
    
    startHeartbeat() {
        if (this.heartbeatInterval) {
            clearInterval(this.heartbeatInterval);
        }
        
        this.heartbeatInterval = setInterval(() => {
            if (this.ws && this.ws.readyState === WebSocket.OPEN) {
                this.ws.send(JSON.stringify({
                    type: 'ping',
                    timestamp: Date.now()
                }));
                this.lastHeartbeat = Date.now();
                console.log('Heartbeat sent');
            }
        }, 25000); // Send ping every 25 seconds
    }
    
    handleMessage(data) {
        try {
            const message = JSON.parse(data);
            console.log('Received message:', message.type);
            
            switch (message.type) {
                case 'auth_success':
                    this.handleAuthSuccess(message);
                    break;
                    
                case 'auth_error':
                    console.error('Authentication error:', message.message);
                    this.triggerEvent('auth_error', message);
                    break;
                    
                case 'message':
                    this.handleNewMessage(message);
                    break;
                    
                case 'message_delivered':
                    this.handleMessageDelivered(message);
                    break;
                    
                case 'read_receipt':
                    this.handleReadReceipt(message);
                    break;
                    
                case 'typing':
                    this.handleTypingIndicator(message);
                    break;
                    
                case 'ping':
                    this.handlePing(message);
                    break;
                    
                case 'pong':
                    this.handlePong(message);
                    break;
                    
                case 'user_online':
                    this.handleUserOnline(message);
                    break;
                    
                case 'user_offline':
                    this.handleUserOffline(message);
                    break;
                    
                default:
                    console.log('Unknown message type:', message.type);
            }
        } catch (error) {
            console.error('Error parsing message:', error);
        }
    }
    
    handleAuthSuccess(message) {
        this.isAuthenticated = true;
        this.connectionId = message.connectionId;
        console.log('Authenticated successfully:', this.connectionId);
        
        // Trigger auth success event
        this.triggerEvent('auth_success', message);
    }
    
    handlePing(message) {
        console.log('Ping received from server');
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify({
                type: 'pong',
                timestamp: Date.now()
            }));
        }
    }
    
    handlePong(message) {
        console.log('Pong received from server');
        this.lastHeartbeat = Date.now();
    }
    
    handleNewMessage(message) {
        const isCurrentConversation = this.activeConversation && 
            ((message.from.type === this.activeConversation.type && 
              message.from.id === this.activeConversation.id) ||
             (this.config.userType === message.from.type && 
              this.config.userId === message.from.id));
        
        console.log('New message received, current conversation:', isCurrentConversation);
        
        // Add message to UI
        this.addMessageToUI(message, false);
        
        // If not current conversation, increment unread count
        if (!isCurrentConversation) {
            this.incrementUnreadCount(message.from.id);
        }
        
        // Mark as read if it's the current conversation
        if (isCurrentConversation) {
            this.markAsRead([message.messageId]);
        }
        
        // Play notification sound if needed
        if (!isCurrentConversation) {
            this.playNotificationSound();
        }
        
        // Trigger new message event
        this.triggerEvent('new_message', message);
    }
    
    handleMessageDelivered(message) {
        console.log('Message delivered:', message.messageId);
        // Update message status in UI
        this.updateMessageStatus(message.messageId, 'delivered');
        
        // Trigger event
        this.triggerEvent('message_delivered', message);
    }
    
    handleReadReceipt(message) {
        console.log('Read receipt:', message.messageIds);
        // Update message status in UI
        message.messageIds.forEach(msgId => {
            this.updateMessageStatus(msgId, 'read');
        });
        
        // Trigger event
        this.triggerEvent('read_receipt', message);
    }
    
    handleTypingIndicator(message) {
        console.log('Typing indicator:', message.from.id, message.isTyping);
        // Show/hide typing indicator
        if (message.isTyping) {
            this.showTypingIndicator(message.from);
        } else {
            this.hideTypingIndicator(message.from.id);
        }
        
        // Trigger event
        this.triggerEvent('typing', message);
    }
    
    handleUserOnline(message) {
        console.log('User online:', message.user.id);
        this.onlineUsers.add(`${message.user.type}:${message.user.id}`);
        this.updateUserStatus(message.user, true);
        
        // Trigger event
        this.triggerEvent('user_online', message);
    }
    
    handleUserOffline(message) {
        console.log('User offline:', message.user.id);
        this.onlineUsers.delete(`${message.user.type}:${message.user.id}`);
        this.updateUserStatus(message.user, false);
        
        // Trigger event
        this.triggerEvent('user_offline', message);
    }
    
    // Send message
    sendMessage(to, content) {
        if (!this.isAuthenticated || !content.trim()) {
            console.log('Cannot send message: not authenticated or empty content');
            return null;
        }
        
        const messageId = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        const timestamp = new Date().toISOString();
        
        const message = {
            type: 'message',
            from: {
                type: this.config.userType,
                id: this.config.userId,
                name: this.config.userName
            },
            to: to,
            content: content.trim(),
            messageId: messageId,
            timestamp: timestamp
        };
        
        console.log('Sending message:', message);
        
        // Send via WebSocket
        this.ws.send(JSON.stringify(message));
        
        // Add to UI immediately (optimistic update)
        this.addMessageToUI({
            ...message,
            isDelivered: false
        }, true);
        
        return messageId;
    }
    
    // Send typing indicator
    sendTypingIndicator(to, isTyping) {
        if (!this.isAuthenticated) {
            console.log('Cannot send typing indicator: not authenticated');
            return;
        }
        
        const typingMessage = {
            type: 'typing',
            from: {
                type: this.config.userType,
                id: this.config.userId
            },
            to: to,
            isTyping: isTyping
        };
        
        console.log('Sending typing indicator:', typingMessage);
        this.ws.send(JSON.stringify(typingMessage));
    }
    
    // Mark messages as read
    markAsRead(messageIds) {
        if (!this.isAuthenticated || !messageIds.length) {
            console.log('Cannot mark as read: not authenticated or no message IDs');
            return;
        }
        
        const readMessage = {
            type: 'read',
            reader: {
                type: this.config.userType,
                id: this.config.userId
            },
            messageIds: messageIds,
            chatPartner: this.activeConversation
        };
        
        console.log('Marking as read:', readMessage);
        this.ws.send(JSON.stringify(readMessage));
    }
    
    // Get online status
    getOnlineStatus(userType, userId) {
        return this.onlineUsers.has(`${userType}:${userId}`);
    }
    
    // Event system
    setupEventListeners() {
        this.events = {};
    }
    
    on(event, callback) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(callback);
    }
    
    off(event, callback) {
        if (!this.events[event]) return;
        
        const index = this.events[event].indexOf(callback);
        if (index > -1) {
            this.events[event].splice(index, 1);
        }
    }
    
    triggerEvent(event, data) {
        if (!this.events[event]) return;
        
        this.events[event].forEach(callback => {
            try {
                callback(data);
            } catch (error) {
                console.error(`Error in ${event} event handler:`, error);
            }
        });
    }
    
    // Abstract methods (to be implemented by specific UIs)
    addMessageToUI(message, isOwnMessage) {
        console.log('Abstract addMessageToUI called, implement in child class');
    }
    
    updateMessageStatus(messageId, status) {
        console.log('Abstract updateMessageStatus called, implement in child class');
    }
    
    showTypingIndicator(user) {
        console.log('Abstract showTypingIndicator called, implement in child class');
    }
    
    hideTypingIndicator(userId) {
        console.log('Abstract hideTypingIndicator called, implement in child class');
    }
    
    updateUserStatus(user, isOnline) {
        console.log('Abstract updateUserStatus called, implement in child class');
    }
    
    incrementUnreadCount(userId) {
        console.log('Abstract incrementUnreadCount called, implement in child class');
    }
    
    // LINE YANG HARUS DIPERBAIKI (sekitar line 330 di file chat_system.js):
playNotificationSound() {
    console.log('🔊 [DEBUG] playNotificationSound() called');
    
    try {
        const audioPath = '/sistemkos/asset/sounds/notification.mp3';
        console.log('🔊 [DEBUG] Audio path:', audioPath);
        
        const audio = new Audio(audioPath);
        console.log('🔊 [DEBUG] Audio object created:', audio);
        
        audio.volume = 0.3;
        console.log('🔊 [DEBUG] Volume set to:', audio.volume);
        
        // Test if audio file exists
        audio.addEventListener('loadeddata', () => {
            console.log('✅ [DEBUG] Audio file loaded successfully');
        });
        
        audio.addEventListener('error', (e) => {
            console.error('❌ [DEBUG] Audio load error:', e);
            console.error('❌ [DEBUG] Audio error details:', {
                code: audio.error?.code,
                message: audio.error?.message
            });
        });
        
        const playPromise = audio.play();
        console.log('🔊 [DEBUG] Play promise:', playPromise);
        
        if (playPromise !== undefined) {
            playPromise
                .then(() => {
                    console.log('✅ [DEBUG] Audio played successfully');
                })
                .catch(error => {
                    console.error('❌ [DEBUG] Audio play failed:', error);
                    console.error('❌ [DEBUG] Error name:', error.name);
                    console.error('❌ [DEBUG] Error message:', error.message);
                });
        }
    } catch (error) {
        console.error('❌ [DEBUG] Exception in playNotificationSound:', error);
        console.error('❌ [DEBUG] Stack trace:', error.stack);
    }
}
    
    // Utility methods
    escapeHtml(text) {
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }
    
    formatTime(timestamp) {
        const date = new Date(timestamp);
        return date.toLocaleTimeString([], { 
            hour: '2-digit', 
            minute: '2-digit' 
        });
    }
    
    formatDate(timestamp) {
        const date = new Date(timestamp);
        const now = new Date();
        const diff = now - date;
        
        if (diff < 86400000) { // Less than 24 hours
            return this.formatTime(timestamp);
        } else if (diff < 604800000) { // Less than 7 days
            return date.toLocaleDateString([], { weekday: 'short' });
        } else {
            return date.toLocaleDateString([], { 
                month: 'short', 
                day: 'numeric' 
            });
        }
    }
}