package top.r3944realms.ltdmanager.module

import kotlinx.coroutines.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import top.r3944realms.ltdmanager.module.common.CommandParser
import top.r3944realms.ltdmanager.module.common.filter.TriggerMessageFilter
import top.r3944realms.ltdmanager.module.common.filter.type.IgnoreSelfFilter
import top.r3944realms.ltdmanager.module.common.filter.type.MultiCommandFilter
import top.r3944realms.ltdmanager.module.common.filter.type.NewMessageFilter
import top.r3944realms.ltdmanager.napcat.data.ID
import top.r3944realms.ltdmanager.napcat.data.MessageElement
import top.r3944realms.ltdmanager.napcat.data.MessageType
import top.r3944realms.ltdmanager.napcat.data.msghistory.MsgHistorySpecificMsg
import top.r3944realms.ltdmanager.napcat.event.group.GetGroupShutListEvent
import top.r3944realms.ltdmanager.napcat.request.group.GetGroupShutListRequest
import top.r3944realms.ltdmanager.napcat.request.group.SetGroupBanRequest
import top.r3944realms.ltdmanager.napcat.request.other.SendGroupMsgRequest
import top.r3944realms.ltdmanager.utils.LoggerUtil
import java.io.File
import kotlin.random.Random

/**
 * 指令触发禁言模块
 */
class BanModule(
    moduleName: String,
    private val groupMessagePollingModule : GroupMessagePollingModule,
    private val selfId: Long,
    private val adminsId: List<Long> = listOf(),
    muteCommandPrefixList: List<String> = listOf("mute"), // 默认命令前缀
    unmuteCommandPrefixList: List<String> = listOf("unmute"),
    private val minBanMinutes: Int = 1,
    private val maxBanMinutes: Int = 15,
    private val factorX: Int = 2,         // 系数 x，禁言倍数

) : BaseModule(Modules.BAN, moduleName), PersistentState<BanModule.BanState> {

    private val banCommandParse = CommandParser(muteCommandPrefixList)
    private val pardonCommandParse = CommandParser(unmuteCommandPrefixList)
    private val multiCommandFilter = MultiCommandFilter(listOf(banCommandParse, pardonCommandParse))
    private val stateFile: File = getStateFileInternal("command_ban_state.json", name)
    private val stateBackupFile: File = getStateFileInternal("command_ban_state.json.bak", name)
    private var banState = loadState()
    override fun getState(): BanState = banState

    private val triggerFilter by lazy {
        TriggerMessageFilter(
            listOf(
                IgnoreSelfFilter(selfId),
                NewMessageFilter { userId ->
                    banState.getLastTriggerTime(userId) to banState.getLastTriggerRealId(userId)
                },
                multiCommandFilter
            )
        )
    }

    private var scope: CoroutineScope? = null


    override fun getStateFileInternal(): File = stateFile

    override fun onLoad() {
        LoggerUtil.logger.info("[$name] 模块已装载，监听群组: ${groupMessagePollingModule.targetGroupId}")
        scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
        scope!!.launch {
            LoggerUtil.logger.info("[$name] 启动消息监听协程")
            groupMessagePollingModule.messagesFlow.collect { messages ->
                handleMessages(messages)
            }
        }
    }

    override suspend fun onUnload() {
        LoggerUtil.logger.info("[$name] 模块卸载，取消协程")
        scope?.cancel()
    }

    private suspend fun handleMessages(messages: List<MsgHistorySpecificMsg>) {
        // 先过一遍过滤器，只有符合条件的才进入后续处理
        val filtered = triggerFilter.filter(messages)
        for (msg in filtered) {
            processBanCommand(msg)
            processUnBanCommand(msg)
        }
    }
    /**
     * 将 SpecificMsg 中的 message 段拼成一条“可解析文本”。
     * - text 段直接拼接
     * - 如果消息段里包含 @（在 MessageData 中为 qq 字段），则拼成 "@{qq}"，方便 parseMentionToUserId 解析
     */
    private fun MsgHistorySpecificMsg.plainText(): String {
        return this.message.joinToString(" ") { seg ->
            // 如果 message element 包含 qq 字段（即@用户），优先使用它
            seg.data.qq?.let { "@${it}" } ?: (seg.data.text ?: "")
        }.trim()
    }
    /**
     * 从消息段中提取所有被 @ 的用户 ID
     */
    private fun MsgHistorySpecificMsg.getMentionedUserIds(): List<ID> {
        return this.message
            .filter { it.type == MessageType.At && it.data.qq != null }
            .mapNotNull { it.data.qq }
            .distinctBy {
                when (it) {
                    is ID.StringValue -> it.value
                    is ID.LongValue -> it.value
                }
            }
    }
    private suspend fun processUnBanCommand(msg: MsgHistorySpecificMsg) {
        try {
            pardonCommandParse.parseCommand(msg.plainText()) ?: return
            // 获取所有被 @ 的用户
            val mentionedUserIds = msg.getMentionedUserIds().map {
                when (it) {
                    is ID.StringValue -> it.value.toLong()
                    is ID.LongValue -> it.value
                }
            } // List<Long>
            val send =
                napCatClient.send<GetGroupShutListEvent>(GetGroupShutListRequest(ID.long(groupMessagePollingModule.targetGroupId)))
            val muteList = send.data.map { it.uin.toLong() }
            for (target in mentionedUserIds) {
                if(target !in muteList) {
                    sendGroupMessage("❌ 目标用户未被禁言",
                        msg.realId
                    )
                } else {
                    banUser(ID.long(target), groupMessagePollingModule.targetGroupId, 0)
                    sendGroupMessage(
                        "✅ 已解禁对方@(${target})",
                        msg.realId
                    )
                }

            }

            // 更新状态
            banState = banState.updateLastTrigger(msg.userId, msg.realId, msg.time)
            saveState(banState)
        } catch (e: Exception) {
            LoggerUtil.logger.error("[$name] 执行解禁言指令失败", e)
            sendGroupMessage("❌ 执行解禁言失败，请检查解指令格式或权限", msg.realId)
            banState = banState.updateLastTrigger(msg.sender.userId, msg.realId, msg.time)
            saveState(banState)
        }
    }
    private suspend fun processBanCommand(msg: MsgHistorySpecificMsg) {
        try {
            val parsed = banCommandParse.parseCommand(msg.plainText()) ?: return
            val (_, argument) = parsed

            val parts = argument.split(" ").filter { it.isNotBlank() }

            // 解析禁言时间
            val durationMinutes = parts.getOrNull(0)?.toIntOrNull()
                ?: Random.nextInt(minBanMinutes, maxBanMinutes + 1)
            val durationSeconds = durationMinutes.coerceIn(minBanMinutes, maxBanMinutes) * 60

            // 获取所有被 @ 的用户
            val mentionedUserIds = msg.getMentionedUserIds() // List<ID>
            val targets = mentionedUserIds.ifEmpty { listOf(ID.long(msg.sender.userId)) }

            for (target in targets) {
                val targetLongId = when (target) {
                    is ID.StringValue -> target.value.toLong()
                    is ID.LongValue -> target.value
                }

                // 权限检查：非管理员不能禁言多个他人
                if (mentionedUserIds.isNotEmpty() && mentionedUserIds.size != 1 && msg.sender.userId !in adminsId) {
                    sendGroupMessage("❌ 你没有权限使用禁言多用户功能", msg.realId)
                    continue
                }

                // 禁言机器人跳过
                if (targetLongId == selfId) {
                    sendGroupMessage("❌ 你没有权限禁言机器人", msg.realId)
                    continue
                }
                if (targetLongId in adminsId) {
                    sendGroupMessage("❌ 不支持禁言管理员", msg.realId)
                    continue
                }

                // 单 @ 且非自己，可能触发反禁自己
                if (mentionedUserIds.size == 1 && targetLongId != msg.sender.userId && msg.sender.userId !in adminsId) {
                    val dice = Random.nextInt(1, 7) // 1~6
                    val chance = when (dice) {
                        6 -> 100
                        5 -> 80
                        4 -> 60
                        3 -> 50
                        2 -> 20
                        1 -> 0
                        else -> 0
                    }

                    val selfDuration = durationSeconds * factorX
                    if (Random.nextInt(0,100) > chance) {
                        // 触发反禁自己
                        banUser(ID.long(msg.sender.userId), groupMessagePollingModule.targetGroupId, selfDuration)
                        sendGroupMessage(
                            "⚠️ 骰子点数: $dice, 成功概率: ${chance}% → 失败，你触发了反禁，禁言 ${selfDuration / 60} 分钟",
                            msg.realId
                        )
                    } else {
                        // 未触发反禁自己，禁言目标
                        banUser(target, groupMessagePollingModule.targetGroupId, durationSeconds)
                        sendGroupMessage(
                            "✅ 骰子点数: $dice, 成功概率: ${chance}% → 成功禁言 <@${targetLongId}>",
                            msg.realId
                        )
                    }
                } else {
                    // 多 @ 或管理员操作，直接禁言目标
                    banUser(target, groupMessagePollingModule.targetGroupId, durationSeconds)
                    sendGroupMessage(
                        if (targetLongId == msg.sender.userId) {
                            "✅ 你已被禁言 ${durationSeconds/ 60} 分钟"
                        } else {
                            "✅ 已禁言 <@${targetLongId}> ${durationSeconds/ 60} 分钟"
                        },
                        msg.realId
                    )
                }


            }
            // 更新状态
            banState = banState.updateLastTrigger(msg.userId, msg.realId, msg.time)
            saveState(banState)
        } catch (e: Exception) {
            LoggerUtil.logger.error("[$name] 执行禁言指令失败", e)
            sendGroupMessage("❌ 执行禁言失败，请检查指令格式或权限", msg.realId)
            banState = banState.updateLastTrigger(msg.sender.userId, msg.realId, msg.time)
            saveState(banState)
        }
    }

    private suspend fun banUser(userId: ID, groupId: Long, seconds: Int) {
        val request = SetGroupBanRequest(
            duration = seconds.toDouble(),
            groupId = ID.long(groupId),
            userId = userId
        )
        napCatClient.sendUnit(request)
        LoggerUtil.logger.info("[$name] 已对用户 $userId 执行 $seconds 秒禁言")
    }
    private suspend fun sendGroupMessage(text: String, replyTo: Long? = null) {
        val request = SendGroupMsgRequest(
            MessageElement.reply(ID.long(replyTo ?: 0), text),
            ID.long(groupMessagePollingModule.targetGroupId)
        )
        napCatClient.sendUnit(request)
    }

    override fun info(): String {
        return buildString {
            append("[$name] 指令禁言模块：\n")
            append(" 管理员用户ID: ${adminsId}\n")
            append(" - 用户发送 ${banCommandParse.getCommands().joinToString("、")} 来禁言自己或指定其他用户（需管理员权限）。\n")
            append(" - 支持指定禁言分钟数或随机分钟数，范围 $minBanMinutes-$maxBanMinutes 分钟。\n")
            append(" - 支持对单个 @ 用户禁言，有概率反禁自己（骰子点数决定概率）。\n")
            append(" - 管理员可以禁言其他用户；非管理员尝试多个禁言对象会收到无权限提示。\n")
            append(" - 用户发送 ${pardonCommandParse.getCommands().joinToString("、")} 来解禁指定用户。\n")
            append(" - 仅支持对单个 @ 用户解禁言。\n")
        }
    }

    override fun help(): String {
        return buildString {
            appendLine("📖 [$name] 使用帮助：")
            appendLine("指令格式：${banCommandParse.getCommands().joinToString("、")} [分钟] [@用户...]")
            appendLine("示例：")
            appendLine(" - <指令>             → 随机禁言自己")
            appendLine(" - <指令> 5           → 禁言自己 5 分钟")
            appendLine(" - <指令> 4 @User123  → 禁言指定用户 4 分钟（可能失败）")
            appendLine(" - <指令> 4 @User123 @User22  → 禁言指定多用户 4 分钟（需在程序管理员列表中）")
            appendLine()
            appendLine("⚠️ 特殊说明：")
            appendLine(" - 如果 @ 单个用户且执行者非需在程序管理员，有 y% 概率触发反禁自己，")
            appendLine("   骰子点数决定概率：6 → 100%, 5 → 80%, 4 → 60%, 3 → 50%, 2 → 20%, 1 → 0%")
            appendLine(" - 禁言机器人自身不会生效")
            appendLine(" - 禁言状态会自动保存以便下次使用")
            appendLine()
            appendLine("指令格式：${pardonCommandParse.getCommands().joinToString("、")} [@用户]")
            appendLine("示例：")
            appendLine(" - <指令> @User123  → 解禁指定用户")
        }
    }

    // ---------------- 持久化 ----------------
    @Serializable
    data class UserBanDetail(
        val realId: Long,
        val time: Long,
    )

    @Serializable
    data class BanState(
        val map: Map<Long, UserBanDetail> = emptyMap()
    ) {
        fun getLastTriggerTime(userId: Long): Long = map[userId]?.time ?: -1
        fun getLastTriggerRealId(userId: Long): Long = map[userId]?.realId ?: -1

        fun updateLastTrigger(userId: Long, realId: Long, time: Long = -1): BanState {
            val old = map[userId]
            val newTime = if (time != -1L) time else old?.time ?: -1
            val newMap = map.toMutableMap().apply {
                put(userId, UserBanDetail(realId, newTime))
            }
            return copy(map = newMap)
        }
    }

    override fun saveState(state: BanState) {
        try {
            if (stateFile.exists()) stateFile.copyTo(stateBackupFile, overwrite = true)
            stateFile.writeText(Json.encodeToString(state))
        } catch (e: Exception) {
            LoggerUtil.logger.error("[$name] 保存状态失败", e)
        }
    }

    override fun loadState(): BanState {
        return try {
            val fileToRead = when {
                stateFile.exists() -> stateFile
                stateBackupFile.exists() -> stateBackupFile
                else -> null
            } ?: return BanState()

            Json.decodeFromString<BanState>(fileToRead.readText())
        } catch (e: Exception) {
            LoggerUtil.logger.warn("[$name] 读取状态失败", e)
            BanState()
        }
    }
}
