const { createApp } = Vue;

// WebSocket服务类
class WebSocketService {
    constructor() {
        this.connections = new Map();
        this.reconnectAttempts = new Map();
        this.maxReconnectAttempts = 5;
        this.reconnectDelay = 1000;
    }

    connect(squareId, onMessage, onStatusChange) {
        const wsUrl = `wss://www.hlsq.asia/ws/?token=${squareId}`;

        try {
            const ws = new WebSocket(wsUrl);
            ws.binaryType = 'arraybuffer';

            ws.onopen = () => {
                console.log(`WebSocket ${squareId} connected`);
                onStatusChange(true);
                this.reconnectAttempts.set(squareId, 0);

                // 发送进入实例消息（protobuf）
                protoUtils.readyPromise.then(() => {
                    const enterInstanceBuffer = protoUtils.createEnterInstanceMessage(1);
                    if (enterInstanceBuffer) {
                        this.sendMessage(ws, enterInstanceBuffer);
                    }
                });
            };

            ws.onclose = (e) => {
                console.log(`WebSocket ${squareId} disconnected:`, e.code, e.reason);
                onStatusChange(false);
                this.connections.delete(squareId);

                // 自动重连
                this.scheduleReconnect(squareId, onMessage, onStatusChange);
            };

            ws.onerror = (error) => {
                console.error(`WebSocket ${squareId} error:`, error);
            };

            ws.onmessage = (event) => {
                try {
                    onMessage(event.data, squareId);
                } catch (error) {
                    console.error('Error processing message:', error);
                }
            };

            this.connections.set(squareId, ws);
        } catch (error) {
            console.error(`WebSocket ${squareId} init error:`, error);
        }
    }

    sendMessage(ws, data) {
        if (ws.readyState === WebSocket.OPEN) {
            try {
                if (data instanceof ArrayBuffer || data instanceof Uint8Array) {
                    ws.send(data);
                } else {
                    console.error('Attempted to send non-binary data through binary channel.');
                }
            } catch (error) {
                console.error('Failed to send message:', error);
            }
        }
    }

    // 发送动作消息
    sendAction(squareId, actionId, x, y) {
        const ws = this.connections.get(squareId);
        if (!ws || ws.readyState !== WebSocket.OPEN) {
            console.warn(`Cannot send action: WebSocket ${squareId} not connected`);
            return false;
        }

        protoUtils.readyPromise.then(() => {
            const actionBuffer = protoUtils.createActionMessage(actionId, x, y);
            if (actionBuffer) {
                this.sendMessage(ws, actionBuffer);
                console.log(`Action sent to square ${squareId}: actionId=${actionId}, x=${x}, y=${y}`);
                return true;
            }
        });
        
        return false;
    }

    // 发送方向动作消息
    sendDirectionAction(squareId, directionBits) {
        const ws = this.connections.get(squareId);
        if (!ws || ws.readyState !== WebSocket.OPEN) {
            console.warn(`Cannot send direction action: WebSocket ${squareId} not connected`);
            return false;
        }

        protoUtils.readyPromise.then(() => {
            const actionBuffer = protoUtils.createDirectionActionMessage(directionBits);
            if (actionBuffer) {
                this.sendMessage(ws, actionBuffer);
                console.log(`Direction action sent to square ${squareId}: directionBits=${directionBits}`);
                return true;
            }
        });
        
        return false;
    }

    scheduleReconnect(squareId, onMessage, onStatusChange) {
        const attempts = this.reconnectAttempts.get(squareId) || 0;

        if (attempts < this.maxReconnectAttempts) {
            const delay = this.reconnectDelay * Math.pow(2, attempts);
            this.reconnectAttempts.set(squareId, attempts + 1);

            setTimeout(() => {
                console.log(`Attempting to reconnect WebSocket ${squareId} (attempt ${attempts + 1})`);
                this.connect(squareId, onMessage, onStatusChange);
            }, delay);
        } else {
            console.error(`Max reconnection attempts reached for WebSocket ${squareId}`);
        }
    }

    disconnect(squareId) {
        const ws = this.connections.get(squareId);
        if (ws) {
            ws.close();
            this.connections.delete(squareId);
        }
    }

    disconnectAll() {
        this.connections.forEach((ws, squareId) => {
            this.disconnect(squareId);
        });
    }
}

// 方块组件
const SquareComponent = {
    props: ['squareId', 'connected', 'dots'],
    template: `
        <div class="square">
            <div class="connection-dot" :class="{ connected: connected }"></div>
            <div class="loading-indicator" v-if="!connected">
                <div class="spinner"></div>
            </div>
            <div 
                v-for="(dot, index) in dots" 
                :key="dot.uid"
                class="game-dot"
                :class="{ 'player-controlled': dot.isPlayerControlled }"
                :style="{ left: dot.x + 'px', top: transformY(dot.y) + 'px' }"
            ></div>
        </div>
    `,
    methods: {
        // 转换Y坐标，使左下角为原点
        transformY(y) {
            // 假设方块高度为400px（从GameConfig获取）
            const height = GameConfig.game.gridSize.height;
            // 将y坐标从"从下到上"转换为"从上到下"
            return height - y;
        }
    }
};

// 主应用组件
const App = {
    components: {
        'square-component': SquareComponent
    },
    template: `
        <div class="app-container">
            <div class="grid-container">
                <square-component
                    v-for="(square, index) in squares"
                    :key="index"
                    :square-id="index + 1"
                    :connected="square.connected"
                    :dots="square.dots"
                    @mouseenter="setActiveSquare(index + 1)"
                    @mouseleave="clearActiveSquare()"
                ></square-component>
            </div>
            <div class="status-bar" v-if="showStatusBar">
                <div class="status-item">
                    连接状态: {{ connectedCount }}/{{ squares.length }}
                </div>
                <div class="status-item">
                    总圆点数: {{ totalDots }}
                </div>
                <div class="status-item" v-if="activeSquareId">
                    当前方块: {{ activeSquareId }}
                </div>
                <div class="status-item" v-if="directionState.active">
                    方向键: {{ directionStateText }}
                </div>
            </div>
        </div>
    `,
    data() {
        return {
            squares: [
                { connected: false, dots: [] },
                { connected: false, dots: [] },
                { connected: false, dots: [] },
                { connected: false, dots: [] }
            ],
            wsService: null,
            showStatusBar: true,
            activeSquareId: null,
            directionState: {
                active: false,
                w: false, // 1
                s: false, // 2
                a: false, // 4
                d: false  // 8
            },
            directionKeyCodes: {
                'KeyW': 'w',
                'KeyS': 's',
                'KeyA': 'a',
                'KeyD': 'd',
                // 兼容箭头键
                'ArrowUp': 'w',
                'ArrowDown': 's',
                'ArrowLeft': 'a',
                'ArrowRight': 'd'
            }
        }
    },
    computed: {
        connectedCount() {
            return this.squares.filter(square => square.connected).length;
        },
        totalDots() {
            return this.squares.reduce((total, square) => total + square.dots.length, 0);
        },
        // 计算方向状态文本
        directionStateText() {
            const keys = [];
            if (this.directionState.w) keys.push('W');
            if (this.directionState.s) keys.push('S');
            if (this.directionState.a) keys.push('A');
            if (this.directionState.d) keys.push('D');
            return keys.join('+') || '无';
        },
        // 计算方向位
        directionBits() {
            let bits = 0;
            if (this.directionState.w) bits |= 1; // W = 1
            if (this.directionState.s) bits |= 2; // S = 2
            if (this.directionState.a) bits |= 4; // A = 4
            if (this.directionState.d) bits |= 8; // D = 8
            return bits;
        }
    },
    mounted() {
        this.wsService = new WebSocketService();
        this.initializeConnections();

        // 添加键盘事件监听
        window.addEventListener('keydown', this.handleKeyDown);
        window.addEventListener('keyup', this.handleKeyUp);
        
        // 添加键盘快捷键
        this.addKeyboardShortcuts();
    },
    beforeUnmount() {
        if (this.wsService) {
            this.wsService.disconnectAll();
        }
        
        // 移除键盘事件监听
        window.removeEventListener('keydown', this.handleKeyDown);
        window.removeEventListener('keyup', this.handleKeyUp);
    },
    methods: {
        initializeConnections() {
            this.squares.forEach((square, index) => {
                const squareId = index + 1;
                this.wsService.connect(
                    squareId,
                    this.handleMessage,
                    (connected) => this.updateConnectionStatus(index, connected)
                );
            });
        },

        updateConnectionStatus(index, connected) {
            this.squares[index].connected = connected;
        },

        handleMessage(rawData, squareId) {
            const squareIndex = squareId - 1;

            try {
                // 仅处理二进制 protobuf 消息
                if (rawData instanceof ArrayBuffer || rawData instanceof Uint8Array) {
                    const arrayBuf = rawData instanceof Uint8Array ? rawData : new Uint8Array(rawData);
                    const outerMsg = protoUtils.encoder.decodeMessage(arrayBuf);
                    if (!outerMsg) return;

                    const msgId = outerMsg.ID;
                    const msgEnum = protoUtils.encoder.MessageID;
                    
                    // 根据消息ID处理不同类型的消息
                    switch (msgId) {
                        case msgEnum.MESSAGE_ID_POSITION: {
                            // 处理位置更新消息
                            const S2C_Position = protoUtils.encoder.root.lookupType('S2C_Position');
                            const positionMsg = S2C_Position.decode(outerMsg.Payload);
                            
                            // 处理所有位置信息
                            if (positionMsg.Info && positionMsg.Info.length > 0) {
                                positionMsg.Info.forEach(info => {
                                    // 注意：坐标已经是以左下角为原点，保持原样
                                    if (utils.validateCoordinates(info.X, info.Y)) {
                                        // 查找是否已存在该UID的点
                                        const existingDotIndex = this.squares[squareIndex].dots.findIndex(dot => dot.uid === info.UID);
                                        
                                        if (existingDotIndex !== -1) {
                                            // 已存在，更新位置
                                            this.squares[squareIndex].dots[existingDotIndex].x = info.X;
                                            this.squares[squareIndex].dots[existingDotIndex].y = info.Y;
                                            this.squares[squareIndex].dots[existingDotIndex].timestamp = Date.now();
                                            console.log(`Dot updated for square ${squareId}, UID ${info.UID}: (${info.X}, ${info.Y})`);
                                        } else {
                                            // 不存在，创建新点
                                            this.squares[squareIndex].dots.push({
                                                x: info.X,
                                                y: info.Y,
                                                timestamp: Date.now(),
                                                uid: info.UID,
                                                // 判断是否是玩家控制的点（假设UID为当前squareId的是玩家控制的）
                                                isPlayerControlled: info.UID === squareId
                                            });
                                            
                                            // 限制每个方块的圆点数量，避免内存泄漏
                                            if (this.squares[squareIndex].dots.length > GameConfig.game.maxDotsPerSquare) {
                                                this.squares[squareIndex].dots.shift();
                                            }
                                            
                                            console.log(`New dot added to square ${squareId} at (${info.X}, ${info.Y}) for UID ${info.UID}`);
                                        }
                                    }
                                });
                            }
                            break;
                        }
                        
                        case msgEnum.MESSAGE_ID_ENTER_INSTANCE: {
                            // 处理进入实例响应消息
                            const S2C_EnterInstance = protoUtils.encoder.root.lookupType('S2C_EnterInstance');
                            const enterInstanceMsg = S2C_EnterInstance.decode(outerMsg.Payload);
                            
                            // 如果有位置信息，添加到对应方块
                            if (enterInstanceMsg.Info) {
                                const info = enterInstanceMsg.Info;
                                // 注意：坐标已经是以左下角为原点，保持原样
                                if (utils.validateCoordinates(info.X, info.Y)) {
                                    // 查找是否已存在该UID的点
                                    const existingDotIndex = this.squares[squareIndex].dots.findIndex(dot => dot.uid === info.UID);
                                    
                                    if (existingDotIndex !== -1) {
                                        // 已存在，更新位置
                                        this.squares[squareIndex].dots[existingDotIndex].x = info.X;
                                        this.squares[squareIndex].dots[existingDotIndex].y = info.Y;
                                        this.squares[squareIndex].dots[existingDotIndex].timestamp = Date.now();
                                        this.squares[squareIndex].dots[existingDotIndex].isInitial = true;
                                        this.squares[squareIndex].dots[existingDotIndex].isPlayerControlled = info.UID === squareId;
                                        console.log(`Initial position updated for square ${squareId}, UID ${info.UID}: (${info.X}, ${info.Y})`);
                                    } else {
                                        // 不存在，创建新点
                                        this.squares[squareIndex].dots.push({
                                            x: info.X,
                                            y: info.Y,
                                            timestamp: Date.now(),
                                            uid: info.UID,
                                            isInitial: true, // 标记为初始位置
                                            // 判断是否是玩家控制的点（假设UID为当前squareId的是玩家控制的）
                                            isPlayerControlled: info.UID === squareId
                                        });
                                        
                                        console.log(`Initial position created for square ${squareId}: (${info.X}, ${info.Y}) UID: ${info.UID}`);
                                    }
                                }
                            }
                            break;
                        }
                        
                        default:
                            console.warn('Unhandled message ID:', msgId);
                            break;
                    }
                    return; // 已处理protobuf
                }
            } catch (error) {
                console.error('Error processing message:', error);
            }
        },

        // 设置当前活动方块
        setActiveSquare(squareId) {
            if (this.squares[squareId - 1].connected) {
                this.activeSquareId = squareId;
                this.directionState.active = true;
                console.log(`Active square set to ${squareId}`);
            }
        },
        
        // 清除当前活动方块
        clearActiveSquare() {
            if (this.activeSquareId) {
                // 在清除之前发送一个id=0的action消息
                this.sendDirectionAction(this.activeSquareId, 0);
                
                // 然后清除状态
                this.activeSquareId = null;
                this.directionState.active = false;
                // 重置所有方向键状态
                this.directionState.w = false;
                this.directionState.s = false;
                this.directionState.a = false;
                this.directionState.d = false;
            }
        },
        
        // 处理键盘按下事件
        handleKeyDown(event) {
            if (!this.activeSquareId) return;
            
            const key = this.directionKeyCodes[event.code];
            if (key && this.directionState.hasOwnProperty(key)) {
                // 只有当状态真正变化时才发送
                if (!this.directionState[key]) {
                    this.directionState[key] = true;
                    // 计算新的方向位并发送
                    const directionBits = this.directionBits;
                    this.sendDirectionAction(this.activeSquareId, directionBits);
                }
                event.preventDefault(); // 防止页面滚动
            }
        },
        
        // 处理键盘释放事件
        handleKeyUp(event) {
            if (!this.activeSquareId) return;
            
            const key = this.directionKeyCodes[event.code];
            if (key && this.directionState.hasOwnProperty(key)) {
                // 只有当状态真正变化时才发送
                if (this.directionState[key]) {
                    this.directionState[key] = false;
                    // 计算新的方向位并发送
                    const directionBits = this.directionBits;
                    this.sendDirectionAction(this.activeSquareId, directionBits);
                }
                event.preventDefault();
            }
        },
        
        addKeyboardShortcuts() {
            document.addEventListener('keydown', (e) => {
                switch (e.key) {
                    case 'h':
                        this.showStatusBar = !this.showStatusBar;
                        break;
                    case 'c':
                        this.clearAllDots();
                        break;
                    case 'r':
                        this.reconnectAll();
                        break;
                }
            });
        },

        clearAllDots() {
            this.squares.forEach(square => {
                square.dots = [];
            });
            console.log('All dots cleared');
        },

        reconnectAll() {
            this.wsService.disconnectAll();
            setTimeout(() => {
                this.initializeConnections();
            }, 1000);
            console.log('Reconnecting all WebSockets...');
        },

        // 发送动作消息到服务器
        sendAction(squareId, actionId, x, y) {
            if (this.wsService) {
                return this.wsService.sendAction(squareId, actionId, x, y);
            }
            return false;
        },
        
        // 发送方向动作消息到服务器
        sendDirectionAction(squareId, directionBits) {
            if (this.wsService) {
                return this.wsService.sendDirectionAction(squareId, directionBits);
            }
            return false;
        }
    }
};

createApp(App).mount('#app');