package com.narutohuo.xindazhou.socketio.impl

import com.google.gson.Gson
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}")
            ILog.d("SocketIOService", "当前已保存的监听器数量: ${eventListeners.size} 个事件类型")
            eventListeners.forEach { (event, callbacks) ->
                ILog.d("SocketIOService", "  - $event: ${callbacks.size} 个回调")
            }
            
            // 如果已连接，先断开
            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)
            ILog.d("SocketIOService", "Socket实例创建完成，socket != null: ${socket != null}")
            
            // 预先注册所有已保存的事件监听器（连接前注册，连接成功后会在 EVENT_CONNECT 中再次注册确保正确）
            // 注意：即使这里注册了，连接成功后也会再次注册，确保所有监听器都正确注册
            ILog.d("SocketIOService", "connect: 预先注册 ${eventListeners.size} 个事件类型的监听器...")
            if (eventListeners.isEmpty()) {
                ILog.w("SocketIOService", "⚠️ 警告：eventListeners 为空，没有监听器需要注册！")
            } else {
                registerAllEventListeners(requireConnected = false)
            }
            
            // 添加连接事件监听（触发已注册的回调）
            // 关键：参考 iOS 实现，在连接成功后再次注册所有监听器，确保所有监听器都已注册
            socket?.on(Socket.EVENT_CONNECT) {
                ILog.d("SocketIOService", "✅ SocketIO连接成功")
                
                // 关键：连接成功后，再次注册所有已保存的事件监听器
                // 这样可以确保即使监听器是在连接之后才注册的，也能正确工作
                ILog.d("SocketIOService", "连接成功：再次注册所有事件监听器（${eventListeners.size} 个事件类型）...")
                registerAllEventListeners(requireConnected = true)
                
                // 触发已注册的 "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)
        ILog.d("SocketIOService", "on: 保存事件监听器: $event (当前该事件有 ${eventListeners[event]?.size} 个监听器)")
        
        // 如果socket已连接，立即注册监听器
        if (socket != null && socket!!.connected()) {
            ILog.d("SocketIOService", "on: Socket 已连接，立即注册事件监听器: $event")
            // 注册新的监听器（Socket.IO 的 on() 会添加监听器，不会替换）
            socket?.on(event) { args ->
                try {
                    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()
                    )
                    
                    ILog.d("SocketIOService", "收到事件: $event, data=${response.data}")
                    callback(response)
                } catch (e: Exception) {
                    ILog.e("SocketIOService", "Error handling event: $event", e)
                }
            }
        } else {
            ILog.d("SocketIOService", "on: Socket 未连接，监听器已保存，将在连接成功后自动注册")
        }
    }
    
    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(Gson().toJson(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)
        }
    }
    
    // ========== 内部方法 ==========
    
    /**
     * 注册所有已保存的事件监听器
     * 
     * 参考 iOS 实现：在连接成功后调用此方法，确保所有监听器都已注册
     * 
     * @param requireConnected 是否要求 socket 已连接（连接前注册时设为 false，连接成功后注册时设为 true）
     */
    private fun registerAllEventListeners(requireConnected: Boolean = true) {
        if (socket == null) {
            ILog.w("SocketIOService", "registerAllEventListeners: Socket 为 null，无法注册监听器")
            return
        }
        
        if (requireConnected && !socket!!.connected()) {
            ILog.w("SocketIOService", "registerAllEventListeners: Socket 未连接，无法注册监听器")
            return
        }
        
        ILog.d("SocketIOService", "registerAllEventListeners: 开始注册 ${eventListeners.size} 个事件类型的监听器...")
        eventListeners.forEach { (event, callbacks) ->
            ILog.d("SocketIOService", "registerAllEventListeners: 注册事件监听器: $event (${callbacks.size} 个回调)")
            // 关键：先移除该事件的所有旧监听器，避免重复注册
            socket?.off(event)
            // 然后为每个回调注册监听器
            callbacks.forEach { callback ->
                socket?.on(event) { args ->
                    try {
                        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()
                        )
                        
                        ILog.d("SocketIOService", "收到事件: $event, data=${response.data}")
                        callback(response)
                    } catch (e: Exception) {
                        ILog.e("SocketIOService", "Error handling event: $event", e)
                    }
                }
            }
        }
        ILog.d("SocketIOService", "registerAllEventListeners: 所有事件监听器注册完成")
    }
}

