package com.tsmobile.app.data

import com.tsmobile.app.TSBridge
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.util.concurrent.ConcurrentHashMap

/**
 * 应用状态仓库。
 * 管理频道列表、客户端列表、服务器信息等状态。
 */
object Repository {

    private val json = Json { ignoreUnknownKeys = true }

    // --- 频道列表 ---
    private val _channels = MutableStateFlow<List<ChannelInfo>>(emptyList())
    val channels: StateFlow<List<ChannelInfo>> = _channels.asStateFlow()

    // --- 客户端列表 ---
    private val _clients = MutableStateFlow<List<ClientInfo>>(emptyList())
    val clients: StateFlow<List<ClientInfo>> = _clients.asStateFlow()

    // 客户端 Map 索引：ClientID → ClientInfo（O(1) 查找）
    private var clientMap: Map<Int, ClientInfo> = emptyMap()

    // 客户端 UID 索引：UID → ClientInfo（O(1) UID 反查）
    private var clientUidMap: Map<String, ClientInfo> = emptyMap()

    // --- 当前客户端 ID ---
    private val _selfClientId = MutableStateFlow(0)
    val selfClientId: StateFlow<Int> = _selfClientId.asStateFlow()

    // --- 当前频道 ID ---
    private val _currentChannelId = MutableStateFlow("0")
    val currentChannelId: StateFlow<String> = _currentChannelId.asStateFlow()

    // --- 服务器信息 ---
    private val _serverInfo = MutableStateFlow<ServerInfo?>(null)
    val serverInfo: StateFlow<ServerInfo?> = _serverInfo.asStateFlow()

    // --- 按频道 ID 索引的成员列表 ---
    private val _channelClients = MutableStateFlow<Map<String, List<ClientInfo>>>(emptyMap())
    val channelClients: StateFlow<Map<String, List<ClientInfo>>> = _channelClients.asStateFlow()

    /**
     * 执行首次同步。
     * 串行请求频道列表、客户端列表、自身 ID（Go 侧 commandTracker 不支持并发命令的数据行正确分发）。
     * @return true 表示同步成功
     */
    suspend fun performInitialSync(): Boolean {
        try {
            android.util.Log.i("Repository", "performInitialSync: starting sequential requests")
            // 串行请求：Go 侧 commandTracker.collect() 会将数据行归到最高 return_code 的命令，
            // 并发执行 channellist/clientlist/clientinfo 会导致数据行错配，频道列表为空。
            val channels = fetchChannels()
            val clients = fetchClients()
            val (selfId, channelId) = withContext(Dispatchers.IO) {
                val id = TSBridge.getClientID().toInt()
                var cid = TSBridge.getChannelID()
                // 备用方案：如果 GetChannelID() 返回 "0"（GetClientInfo 可能失败），
                // 从客户端列表中获取自身所在的频道 ID
                if (cid == "0" && id > 0) {
                    val selfChannel = clients.find { it.id == id }?.channelId
                    if (selfChannel != null && selfChannel != "0") {
                        android.util.Log.i("Repository", "performInitialSync: getChannelID returned 0, using client list fallback: $selfChannel")
                        cid = selfChannel
                    }
                }
                id to cid
            }

            android.util.Log.i("Repository", "performInitialSync: fetched ${channels.size} channels, ${clients.size} clients, selfId=$selfId, channelId=$channelId")

            // 频道列表为空说明 Go 侧尚未从服务器收到频道数据，视为同步失败（等待重试）
            if (channels.isEmpty()) {
                android.util.Log.w("Repository", "performInitialSync: channels list is empty, server data not ready yet")
                return false
            }

            // 打印频道 parentId 关系，用于检测循环引用
            for (ch in channels) {
                android.util.Log.d("Repository", "Channel: id=${ch.id}, name=${ch.name}, parentId=${ch.parentId}, order=${ch.order}")
            }
            for (cl in clients) {
                android.util.Log.d("Repository", "Client: id=${cl.id}, nickname=${cl.nickname}, channelId=${cl.channelId}")
            }

            // 原子提交
            updateBaseline(channels, clients, selfId, channelId)

            return true
        } catch (e: Exception) {
            android.util.Log.e("Repository", "performInitialSync failed", e)
            return false
        }
    }

    /**
     * 获取频道列表。
     */
    private suspend fun fetchChannels(): List<ChannelInfo> = withContext(Dispatchers.IO) {
        try {
            val jsonStr = TSBridge.getChannelsJSON()
            val channels = json.decodeFromString<List<ChannelInfo>>(jsonStr)
            // 服务器可能返回重复的频道条目，按 ID 去重（保留最后出现的）
            channels.distinctBy { it.id }
        } catch (e: Exception) {
            android.util.Log.e("Repository", "Failed to fetch channels", e)
            emptyList()
        }
    }

    /**
     * 获取客户端列表。
     */
    private suspend fun fetchClients(): List<ClientInfo> = withContext(Dispatchers.IO) {
        try {
            val jsonStr = TSBridge.getClientsJSON()
            val clients = json.decodeFromString<List<ClientInfo>>(jsonStr)
            // 按 ID 去重
            clients.distinctBy { it.id }
        } catch (e: Exception) {
            android.util.Log.e("Repository", "Failed to fetch clients", e)
            emptyList()
        }
    }

    /**
     * 全量刷新客户端列表（通过 clientlist 命令）。
     *
     * notifycliententerview 事件中的 ChannelID 不可靠（SDK 文档标注"未生效"），
     * 因此收到 OnClientEnter 时改用 clientlist 全量获取，确保频道归属正确。
     */
    suspend fun refreshClientList() {
        val clients = fetchClients()
        if (clients.isEmpty()) {
            android.util.Log.w("Repository", "refreshClientList: empty result, skipping update")
            return
        }
        applyClients(clients, _selfClientId.value)
    }

    /**
     * 更新当前频道 ID。
     */
    fun setCurrentChannelId(channelId: String) {
        _currentChannelId.value = channelId
    }

    /**
     * 仅更新频道列表（不覆盖 clients 相关状态）。
     * 用于 refreshChannelsIfNeeded 等部分刷新场景。
     */
    fun updateChannels(channels: List<ChannelInfo>) {
        _channels.value = channels
    }

    /**
     * 应用客户端列表并过滤僵尸会话。
     *
     * 重连时旧连接可能尚未超时（僵尸会话），服务器会对同 UID 的新连接自动改名（如 "name" → "name_1"）。
     * 此处按 UID 过滤：保留当前 selfClientId，移除同 UID 但不同 clid 的僵尸条目。
     */
    private fun applyClients(clients: List<ClientInfo>, selfId: Int) {
        val selfUid = clients.find { it.id == selfId }?.uid
        val filtered = if (selfUid != null) {
            clients.filter { it.id == selfId || it.uid != selfUid }
        } else {
            clients
        }
        if (filtered.size < clients.size) {
            android.util.Log.i("Repository", "Filtered ${clients.size - filtered.size} zombie session(s) from client list")
        }
        _clients.value = filtered
        clientMap = filtered.associateBy { it.id }
        clientUidMap = filtered.associateBy { it.uid }
        _channelClients.value = filtered.groupBy { it.channelId }
        android.util.Log.d("Repository", "applyClients: ${filtered.size} clients (${clients.size} before filtering)")
    }

    /**
     * 更新基线数据。
     */
    fun updateBaseline(
        channels: List<ChannelInfo>,
        clients: List<ClientInfo>,
        selfClientId: Int,
        currentChannelId: String,
    ) {
        _channels.value = channels
        _selfClientId.value = selfClientId
        _currentChannelId.value = currentChannelId

        applyClients(clients, selfClientId)
    }

    /** 查询成员是否存在 */
    fun hasClient(clientId: Int): Boolean = clientMap.containsKey(clientId)

    /** 查询成员信息 */
    fun getClient(clientId: Int): ClientInfo? = clientMap[clientId]

    /** 通过 UID 查询成员信息（O(1)） */
    fun getClientByUid(uid: String): ClientInfo? = clientUidMap[uid]

    /** 查询频道是否存在 */
    fun hasChannel(channelId: String): Boolean = _channels.value.any { it.id == channelId }

    // --- 消息归档 ---
    // 按 (TargetMode, Target) 分组存储，key = "${targetMode}_${targetId}"
    private val messageArchives = ConcurrentHashMap<String, MutableList<ChatMessage>>()

    // 当前查看的会话（用于判断是否需要推送系统通知）
    @Volatile
    var activeChatKey: String? = null
        private set

    /**
     * 归档消息（由 OnTextMessage 调用）。
     * 必须读取 TargetMode 和 Target，不能使用当前页面猜测目标。
     */
    fun archiveMessage(message: ChatMessage) {
        val key = "${message.targetMode}_${message.targetId}"

        val archive = messageArchives.getOrPut(key) { mutableListOf() }
        synchronized(archive) {
            archive.add(message)
            if (archive.size > 500) {
                archive.removeAt(0)
            }
        }
    }

    /**
     * 标记自己发送的消息为已送达（匹配 OnTextMessage 回显）。
     * 优先用 invokerID + content 双重匹配（AAR 已支持 InvokerID），
     * 降级到仅 content 匹配（senderId=0 时）。
     * @return 已确认消息的 ID，未匹配返回 null
     */
    fun confirmMessageDelivery(targetMode: Int, targetId: Long, senderId: Int, content: String): String? {
        val key = "${targetMode}_${targetId}"
        val archive = messageArchives[key] ?: return null

        synchronized(archive) {
            for (i in archive.indices.reversed()) {
                val msg = archive[i]
                if (msg.isSelf &&
                    msg.deliveryState == MessageDeliveryState.PENDING &&
                    msg.content == content &&
                    (senderId == 0 || msg.senderId == senderId)
                ) {
                    archive[i] = msg.copy(deliveryState = MessageDeliveryState.SENT)
                    return msg.id
                }
            }
        }
        return null
    }

    /**
     * 标记指定消息为发送失败（超时未确认）。
     * @return true 表示找到并更新了对应消息
     */
    fun markMessageDeliveryFailed(targetMode: Int, targetId: Long, messageId: String): Boolean {
        val key = "${targetMode}_${targetId}"
        val archive = messageArchives[key] ?: return false

        synchronized(archive) {
            for (i in archive.indices) {
                val msg = archive[i]
                if (msg.id == messageId && msg.deliveryState == MessageDeliveryState.PENDING) {
                    archive[i] = msg.copy(deliveryState = MessageDeliveryState.FAILED)
                    return true
                }
            }
        }
        return false
    }

    /**
     * 标记自己发送的消息为发送失败（超时未确认）。
     * @return 更新的消息 ID 列表
     */
    fun markPendingMessagesFailed(targetMode: Int, targetId: Long): List<String> {
        val key = "${targetMode}_${targetId}"
        val archive = messageArchives[key] ?: return emptyList()
        val failedIds = mutableListOf<String>()

        synchronized(archive) {
            for (i in archive.indices) {
                val msg = archive[i]
                if (msg.isSelf && msg.deliveryState == MessageDeliveryState.PENDING) {
                    archive[i] = msg.copy(deliveryState = MessageDeliveryState.FAILED)
                    failedIds.add(msg.id)
                }
            }
        }
        return failedIds
    }

    /**
     * 获取指定会话的消息列表。
     */
    fun getMessages(targetMode: Int, targetId: Long): List<ChatMessage> {
        val key = "${targetMode}_${targetId}"
        val archive = messageArchives[key] ?: emptyList()
        return synchronized(archive) { archive.toList() }
    }

    /**
     * 设置当前活跃会话（进入聊天页时调用）。
     */
    fun setActiveChat(targetMode: Int?, targetId: Long?) {
        activeChatKey = if (targetMode != null && targetId != null) {
            "${targetMode}_${targetId}"
        } else {
            null
        }
    }

    /**
     * 清理会话数据。
     */
    fun clearSession() {
        _channels.value = emptyList()
        _clients.value = emptyList()
        clientMap = emptyMap()
        clientUidMap = emptyMap()
        _selfClientId.value = 0
        _currentChannelId.value = "0"
        _serverInfo.value = null
        _channelClients.value = emptyMap()
        messageArchives.clear()
        activeChatKey = null
    }

    /**
     * 获取指定频道的客户端列表。
     */
    fun getClientsInChannel(channelId: String): List<ClientInfo> {
        return _channelClients.value[channelId] ?: emptyList()
    }

    /**
     * 获取当前用户所在的频道 ID（O(1) 查找）。
     */
    fun getSelfChannelId(): String {
        return clientMap[_selfClientId.value]?.channelId ?: "0"
    }
}
