package com.system.cloudservice.antiban

import com.system.cloudservice.util.Logger
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger

class RiskSentinel(
    private val onAlert: ((level: Int, message: String) -> Unit)? = null,
) {
    companion object {
        private const val WINDOW_MS = 60_000L
        private const val HOURLY_MS = 3_600_000L
        // AB-01：与服务端 rate_limiter 量产阈值对齐。2026 全网共识：发送 >20 条/分钟
        // 持续即触发临时限制，故分钟上限收敛到 20；小时上限 500→300 更接近真人节律。
        private const val MAX_PER_MINUTE = 20
        private const val MAX_PER_HOUR = 300
        // 连续失败冷却由 30s 提升到 120s，避免被静默降权后快速重试加重风控。
        private const val FAILURE_COOLDOWN_MS = 120_000L
        private const val MAX_CONSECUTIVE_FAILURES = 3
    }

    private val minuteCounter = AtomicInteger(0)
    private val hourCounter = AtomicInteger(0)
    private var minuteWindowStart = System.currentTimeMillis()
    private var hourWindowStart = System.currentTimeMillis()
    private var consecutiveFailures = 0
    private var cooldownUntil = 0L
    private var riskLevel = 0
    private val actionCounts = ConcurrentHashMap<String, AtomicInteger>()

    fun canOperate(action: String? = null): Boolean {
        val now = System.currentTimeMillis()
        if (now < cooldownUntil) return false
        resetWindowsIfNeeded(now)
        return minuteCounter.get() < MAX_PER_MINUTE && hourCounter.get() < MAX_PER_HOUR
    }

    /** AB-06：当前风控等级（0正常/1注意/2警告/3暂停），供批量任务闸门判断 */
    fun currentLevel(): Int = riskLevel

    fun recordAction(action: String) {
        val now = System.currentTimeMillis()
        resetWindowsIfNeeded(now)
        minuteCounter.incrementAndGet()
        hourCounter.incrementAndGet()
        actionCounts.getOrPut(action) { AtomicInteger(0) }.incrementAndGet()
        consecutiveFailures = 0
        checkThresholds()
    }

    fun reportFailure(error: String) {
        consecutiveFailures++
        if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES) {
            riskLevel = 3
            cooldownUntil = System.currentTimeMillis() + FAILURE_COOLDOWN_MS
            Logger.w("RiskSentinel: $MAX_CONSECUTIVE_FAILURES consecutive failures, cooldown ${FAILURE_COOLDOWN_MS / 1000}s")
            onAlert?.invoke(3, "连续${MAX_CONSECUTIVE_FAILURES}次失败，暂停${FAILURE_COOLDOWN_MS / 1000}s")
        }
    }

    fun getStatus(): Map<String, Any?> = mapOf(
        "level" to riskLevel,
        "level_name" to when (riskLevel) { 0 -> "正常"; 1 -> "注意"; 2 -> "警告"; 3 -> "暂停"; else -> "未知" },
        "minute_count" to minuteCounter.get(),
        "hour_count" to hourCounter.get(),
        "consecutive_failures" to consecutiveFailures,
        "cooldown_remaining_ms" to maxOf(0, cooldownUntil - System.currentTimeMillis()),
    )

    private fun resetWindowsIfNeeded(now: Long) {
        if (now - minuteWindowStart > WINDOW_MS) {
            minuteCounter.set(0)
            minuteWindowStart = now
        }
        if (now - hourWindowStart > HOURLY_MS) {
            hourCounter.set(0)
            hourWindowStart = now
        }
    }

    private fun checkThresholds() {
        val prev = riskLevel
        riskLevel = when {
            minuteCounter.get() > MAX_PER_MINUTE * 0.8 || hourCounter.get() > MAX_PER_HOUR * 0.8 -> 2
            minuteCounter.get() > MAX_PER_MINUTE * 0.5 || hourCounter.get() > MAX_PER_HOUR * 0.5 -> 1
            else -> 0
        }
        if (riskLevel > prev) {
            val msg = "风控等级升至 $riskLevel (${minuteCounter.get()}/min, ${hourCounter.get()}/hr)"
            Logger.w("RiskSentinel: $msg")
            onAlert?.invoke(riskLevel, msg)
        }
    }
}
