package com.narutohuo.xindazhou.socketio.impl

import com.alibaba.fastjson2.JSON
import com.narutohuo.xindazhou.core.log.ILog
import com.narutohuo.xindazhou.socketio.api.SocketIOService
import com.narutohuo.xindazhou.socketio.model.SocketIOResponse
import io.socket.client.IO
import io.socket.client.Socket
import org.json.JSONObject

/**
 * SocketIO服务实现类（单例模式）
 * 
 * Socket.IO连接是全局唯一的，多个界面需要共享同一个连接
 * 
 * 注意：请通过 SocketIOServiceFactory.getInstance() 获取实例，不要直接调用此类的 getInstance()
 */
class SocketIOServiceImpl private constructor() : SocketIOService {
    
    companion object {
        @Volatile
        private var INSTANCE: SocketIOServiceImpl? = null
        
        /**
         * 获取SocketIO服务单例（内部方法）
         * 
         * 注意：请通过 SocketIOServiceFactory.getInstance() 获取，保持API一致性
         */
        @JvmStatic
        internal fun getInstance(): SocketIOServiceImpl {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: SocketIOServiceImpl().also { INSTANCE = it }
            }
        }
        
        /**
         * 销毁单例（用于测试或需要重新初始化时）
         */
        @JvmStatic
        fun destroyInstance() {
            INSTANCE?.disconnect()
            INSTANCE = null
        }
    }
    
    private var socket: Socket? = null
    // 存储事件监听器，以便在socket创建后注册
    private val eventListeners = mutableMapOf<String, MutableList<(SocketIOResponse) -> Unit>>()
    
    override fun connect(serverUrl: String, token: String) {
        try {
            ILog.d("SocketIOService", "=== SocketIO连接开始 ===")
            ILog.d("SocketIOService", "服务器地址: $serverUrl")
            ILog.d("SocketIOService", "Token长度: ${token.length}")
            
            // 如果已连接，先断开
            if (socket?.connected() == true) {
                ILog.d("SocketIOService", "检测到已有连接，先断开")
                disconnect()
            }
            
            // 初始化Socket连接
            val options = IO.Options().apply {
                // 添加认证token（通过 HTTP Headers）
                extraHeaders = mapOf("Authorization" to listOf("Bearer $token"))
                // 添加token作为查询参数（备用方案，服务端会优先从 Headers 获取）
                // Socket.IO Java 客户端的 query 参数是 String 格式
                query = "token=$token"
                // 禁用自动重连，改为手动重连（原因：自动重连无法更新 Token）
                // 前后台切换时的重连由 Application 层通过 ProcessLifecycleOwner 处理
                reconnection = false
            }
            
            ILog.d("SocketIOService", "连接配置: Authorization=Bearer $token, query=token=$token")
            
            ILog.d("SocketIOService", "创建Socket实例...")
            socket = IO.socket(serverUrl, options)
            
            // 注册所有已保存的事件监听器
            eventListeners.forEach { (event, callbacks) ->
                callbacks.forEach { callback ->
                    socket?.on(event) { args ->
                        try {
                            // Socket.IO Java 客户端库接收数据时，服务端发送的 Map 会被自动序列化为 JSONObject
                            // 统一转换为 JSON 字符串格式，符合 SocketIOResponse.data 的类型定义
                            val data = if (args.isNotEmpty()) {
                                when (val arg = args[0]) {
                                    is String -> arg
                                    is JSONObject -> arg.toString() // JSONObject.toString() 返回标准 JSON 字符串
                                    else -> JSON.toJSONString(arg)
                                }
                            } else {
                                "{}"
                            }
                            
                            val response = SocketIOResponse(
                                event = event,
                                data = data,
                                timestamp = System.currentTimeMillis()
                            )
                            
                            callback(response)
                        } catch (e: Exception) {
                            ILog.e("SocketIOService", "Error handling event: $event", e)
                        }
                    }
                }
            }
            
            // 添加连接事件监听（触发已注册的回调）
            socket?.on(Socket.EVENT_CONNECT) {
                ILog.d("SocketIOService", "✅ SocketIO连接成功")
                // 触发已注册的 "connect" 事件回调
                val callbacks = eventListeners["connect"] ?: return@on
                val response = SocketIOResponse(
                    event = "connect",
                    data = "{}",
                    timestamp = System.currentTimeMillis()
                )
                callbacks.forEach { it(response) }
            }
            
            socket?.on(Socket.EVENT_DISCONNECT) {
                ILog.d("SocketIOService", "❌ SocketIO连接断开")
                // 触发已注册的 "disconnect" 事件回调
                val callbacks = eventListeners["disconnect"] ?: return@on
                val response = SocketIOResponse(
                    event = "disconnect",
                    data = "{}",
                    timestamp = System.currentTimeMillis()
                )
                callbacks.forEach { it(response) }
            }
            
            socket?.on(Socket.EVENT_CONNECT_ERROR) { args ->
                val errorMsg = args?.getOrNull(0)?.toString() ?: "连接错误"
                ILog.e("SocketIOService", "❌ SocketIO连接错误: $errorMsg")
                ILog.e("SocketIOService", "连接错误详情: args=$args")
                // 触发已注册的 "connect_error" 事件回调
                val callbacks = eventListeners["connect_error"] ?: return@on
                val response = SocketIOResponse(
                    event = "connect_error",
                    data = errorMsg,
                    timestamp = System.currentTimeMillis()
                )
                callbacks.forEach { it(response) }
            }
            
            ILog.d("SocketIOService", "开始连接SocketIO服务器...")
            socket?.connect()
            ILog.d("SocketIOService", "connect()方法调用完成")
        } catch (e: Exception) {
            ILog.e("SocketIOService", "❌ SocketIO连接异常", e)
        }
    }
    
    override fun disconnect() {
        socket?.disconnect()
        socket = null
        // 注意：不清除 eventListeners，这样重新连接时可以自动注册
        ILog.d("SocketIOService", "Disconnected from SocketIO server")
    }
    
    override fun isConnected(): Boolean {
        return socket?.connected() == true
    }
    
    override fun on(event: String, callback: (SocketIOResponse) -> Unit) {
        // 保存事件监听器
        eventListeners.getOrPut(event) { mutableListOf() }.add(callback)
        
        // 如果socket已创建，立即注册
        socket?.on(event) { args ->
            try {
                // Socket.IO Java 客户端库接收数据时，服务端发送的 Map 会被自动序列化为 JSONObject
                // 统一转换为 JSON 字符串格式，符合 SocketIOResponse.data 的类型定义
                val data = if (args.isNotEmpty()) {
                    when (val arg = args[0]) {
                        is String -> arg
                        is JSONObject -> arg.toString() // JSONObject.toString() 返回标准 JSON 字符串
                        else -> JSON.toJSONString(arg)
                    }
                } else {
                    "{}"
                }
                
                val response = SocketIOResponse(
                    event = event,
                    data = data,
                    timestamp = System.currentTimeMillis()
                )
                
                callback(response)
            } catch (e: Exception) {
                ILog.e("SocketIOService", "Error handling event: $event", e)
            }
        }
    }
    
    override fun off(event: String) {
        socket?.off(event)
    }
    
    override fun emit(event: String, data: Any) {
        try {
            val jsonData = when (data) {
                is String -> data
                is JSONObject -> data
                is Map<*, *> -> {
                    // 将 Kotlin Map 转换为 JSONObject（Socket.IO Java 客户端库的标准格式）
                    // netty-socketio 服务端会自动将 JSONObject 反序列化为 Map
                    JSONObject().apply {
                        @Suppress("UNCHECKED_CAST")
                        (data as Map<String, Any>).forEach { (key, value) ->
                            put(key, value)
                        }
                    }
                }
                else -> {
                    // 其他类型先转为 JSON 字符串，再转为 JSONObject
                    JSONObject(JSON.toJSONString(data))
                }
            }
            
            socket?.emit(event, jsonData)
            ILog.d("SocketIOService", "Emitted event: $event, dataType=${jsonData.javaClass.simpleName}")
        } catch (e: Exception) {
            ILog.e("SocketIOService", "Error emitting event: $event", e)
        }
    }
}

