package com.narutohuo.xindazhou.common.socketio.impl

import com.google.gson.Gson
import com.narutohuo.xindazhou.common.log.LogHelper
import com.narutohuo.xindazhou.common.socketio.model.SocketIOResponse
import io.socket.client.IO
import io.socket.client.Socket
import org.json.JSONObject

/**
 * SocketIO 客户端（单例模式）
 * 
 * Socket.IO 连接是全局唯一的，多个界面需要共享同一个连接
 * 这是底层 Socket.IO 客户端的封装，由 SocketIOManager 使用
 */
internal class SocketIOClient private constructor() {
    
    companion object {
        @Volatile
        private var INSTANCE: SocketIOClient? = null
        
        /**
         * 获取 SocketIO 客户端单例
         */
        @JvmStatic
        internal fun getInstance(): SocketIOClient {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: SocketIOClient().also { INSTANCE = it }
            }
        }
        
        /**
         * 销毁单例（用于测试或需要重新初始化时）
         */
        @JvmStatic
        internal fun destroyInstance() {
            INSTANCE?.disconnect()
            INSTANCE = null
        }
    }
    
    private var socket: Socket? = null
    // 存储事件监听器，以便在 socket 创建后注册
    private val eventListeners = mutableMapOf<String, MutableList<(SocketIOResponse) -> Unit>>()
    
    fun connect(serverUrl: String, token: String) {
        try {
            LogHelper.d("SocketIOClient", "=== SocketIO 连接开始 ===")
            LogHelper.d("SocketIOClient", "服务器地址: $serverUrl")
            LogHelper.d("SocketIOClient", "Token 长度: ${token.length}")
            
            // 如果已连接，先断开
            if (socket?.connected() == true) {
                LogHelper.d("SocketIOClient", "检测到已有连接，先断开")
                disconnect()
            }
            
            // 初始化 Socket 连接
            val options = IO.Options().apply {
                // 添加认证 token（通过 HTTP Headers）
                extraHeaders = mapOf("Authorization" to listOf("Bearer $token"))
                // 添加 token 作为查询参数（备用方案）
                query = "token=$token&EIO=1" // 使用 Engine.IO v1 以匹配服务器
                // 禁用自动重连，改为手动重连（原因：自动重连无法更新 Token）
                reconnection = false
            }
            
            LogHelper.d("SocketIOClient", "连接配置: Authorization=Bearer $token, query=token=$token&EIO=1")
            
            LogHelper.d("SocketIOClient", "创建 Socket 实例...")
            socket = IO.socket(serverUrl, options)
            
            // 预先注册所有已保存的事件监听器（连接前注册）
            LogHelper.d("SocketIOClient", "connect: 预先注册 ${eventListeners.size} 个事件类型的监听器...")
            if (eventListeners.isEmpty()) {
                LogHelper.w("SocketIOClient", "⚠️ 警告：eventListeners 为空，没有监听器需要预注册！")
            } else {
                registerAllEventListeners()
            }
            
            // 添加连接事件监听
            socket?.on(Socket.EVENT_CONNECT) {
                LogHelper.d("SocketIOClient", "✅ SocketIO 连接成功")
                
                // 关键：连接成功后，再次注册所有已保存的事件监听器
                // 这样可以确保即使监听器是在连接之后才注册的，也能正确工作
                LogHelper.d("SocketIOClient", "连接成功：再次注册所有事件监听器（${eventListeners.size} 个事件类型）...")
                registerAllEventListeners()
                
                triggerEvent("connect", "{}")
            }
            
            socket?.on(Socket.EVENT_DISCONNECT) {
                LogHelper.d("SocketIOClient", "❌ SocketIO 断开连接")
                triggerEvent("disconnect", "{}")
            }
            
            socket?.on(Socket.EVENT_CONNECT_ERROR) { args ->
                val errorMsg = args?.getOrNull(0)?.toString() ?: "连接错误"
                LogHelper.e("SocketIOClient", "❌ SocketIO 连接错误: $errorMsg")
                triggerEvent("connect_error", errorMsg)
            }
            
            LogHelper.d("SocketIOClient", "开始连接 SocketIO 服务器...")
            socket?.connect()
            LogHelper.d("SocketIOClient", "connect() 方法调用完成")
        } catch (e: Exception) {
            LogHelper.e("SocketIOClient", "❌ SocketIO 连接异常", e)
        }
    }
    
    fun disconnect() {
        socket?.disconnect()
        socket = null
        // 注意：不清除 eventListeners，这样重新连接时可以自动注册
        LogHelper.d("SocketIOClient", "已断开 SocketIO 连接")
    }
    
    fun isConnected(): Boolean {
        return socket?.connected() == true
    }
    
    fun on(event: String, callback: (SocketIOResponse) -> Unit) {
        // 保存事件监听器
        eventListeners.getOrPut(event) { mutableListOf() }.add(callback)
        LogHelper.d("SocketIOClient", "on: 保存事件监听器: $event (当前该事件有 ${eventListeners[event]?.size} 个监听器)")
        
        // 如果 socket 已连接，立即注册该事件的所有监听器（重新注册所有，确保不丢失）
        if (socket != null && socket!!.connected()) {
            LogHelper.d("SocketIOClient", "on: Socket 已连接，重新注册该事件的所有监听器: $event")
            // 先移除该事件的所有旧监听器，然后重新注册所有 callbacks
            socket?.off(event)
            val callbacks = eventListeners[event] ?: return
            callbacks.forEach { cb ->
                registerEventListener(event, cb)
            }
        } else {
            LogHelper.d("SocketIOClient", "on: Socket 未连接，监听器已保存，将在连接成功后自动注册")
        }
    }
    
    fun off(event: String) {
        socket?.off(event)
        eventListeners.remove(event)
    }
    
    fun emit(event: String, data: Any) {
        try {
            val jsonData = when (data) {
                is String -> data
                is JSONObject -> data
                is Map<*, *> -> {
                    // 将 Kotlin Map 转换为 JSONObject
                    JSONObject().apply {
                        @Suppress("UNCHECKED_CAST")
                        (data as Map<String, Any>).forEach { (key, value) ->
                            put(key, value)
                        }
                    }
                }
                else -> {
                    // 其他类型先转为 JSON 字符串，再转为 JSONObject
                    JSONObject(Gson().toJson(data))
                }
            }
            
            socket?.emit(event, jsonData)
            LogHelper.d("SocketIOClient", "发送事件: $event")
        } catch (e: Exception) {
            LogHelper.e("SocketIOClient", "发送事件失败: $event", e)
        }
    }
    
    // ========== 内部方法 ==========
    
    /**
     * 注册所有已保存的事件监听器
     * 
     * 参考 iOS 实现：不先 off，直接为每个 callback 注册监听器
     */
    private fun registerAllEventListeners() {
        if (socket == null) {
            LogHelper.w("SocketIOClient", "registerAllEventListeners: Socket 为 null，无法注册监听器")
            return
        }
        LogHelper.d("SocketIOClient", "registerAllEventListeners: 开始注册 ${eventListeners.size} 个事件类型的监听器...")
        eventListeners.forEach { (event, callbacks) ->
            LogHelper.d("SocketIOClient", "registerAllEventListeners: 注册事件监听器: $event (${callbacks.size} 个回调)")
            // 参考 iOS：不先 off，直接为每个 callback 注册监听器
            // 这样每个 callback 都会收到事件，不会互相覆盖
            callbacks.forEach { callback ->
                registerEventListener(event, callback)
            }
        }
        LogHelper.d("SocketIOClient", "registerAllEventListeners: 所有事件监听器注册完成")
    }
    
    /**
     * 注册单个事件监听器
     */
    private fun registerEventListener(event: String, callback: (SocketIOResponse) -> Unit) {
        socket?.on(event) { args ->
            try {
                // Socket.IO Java 客户端库接收数据时，服务端发送的 Map 会被自动序列化为 JSONObject
                // 统一转换为 JSON 字符串格式
                val data = if (args.isNotEmpty()) {
                    when (val arg = args[0]) {
                        is String -> arg
                        is JSONObject -> arg.toString()
                        else -> Gson().toJson(arg)
                    }
                } else {
                    "{}"
                }
                
                val response = SocketIOResponse(
                    event = event,
                    data = data,
                    timestamp = System.currentTimeMillis()
                )
                
                LogHelper.d("SocketIOClient", "收到事件: $event, data=${response.data}")
                callback(response)
            } catch (e: Exception) {
                LogHelper.e("SocketIOClient", "处理事件失败: $event", e)
            }
        }
    }
    
    /**
     * 触发事件（用于连接/断开等内置事件）
     */
    private fun triggerEvent(event: String, data: String) {
        val callbacks = eventListeners[event] ?: return
        val response = SocketIOResponse(
            event = event,
            data = data,
            timestamp = System.currentTimeMillis()
        )
        callbacks.forEach { it(response) }
    }
}

