package com.tsmobile.app

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.util.Log
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

/**
 * 网络状态监控器 — 检测网络连接变化。
 *
 * 通过 ConnectivityManager.registerDefaultNetworkCallback() 监听网络可用性，
 * 提供 StateFlow 供 ViewModel 层订阅。核心目的是在网络切换（WiFi ↔ 移动数据）
 * 时区分"网络丢失导致的断线"与"服务器主动断线"，从而触发不同的重连策略。
 *
 * 用法：
 * - start() / stop() 控制生命周期（在 ViewModel init/onCleared 中调用）
 * - isAvailable 实时反映当前网络状态
 * - consumeNetworkLossDisconnect() 在 onDisconnected 回调中调用，判断是否应自动重连
 * - reset() 在手动断开/放弃重连时清除追踪状态
 */
class NetworkMonitor(context: Context) {

    companion object {
        private const val TAG = "NetworkMonitor"
        /** 网络丢失后多长时间内触发的 onDisconnected 视为网络原因 */
        private const val RECENT_LOSS_WINDOW_MS = 60_000L
    }

    private val connectivityManager =
        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager

    /** 当前网络是否可用 */
    private val _isAvailable = MutableStateFlow(true) // 乐观假设：初始时网络可用
    val isAvailable: StateFlow<Boolean> = _isAvailable.asStateFlow()

    /** 网络切换计数器：仅在 onLost / onAvailable 时自增（onCapabilitiesChanged 太频繁，不计数） */
    private val _networkChangeCount = MutableStateFlow(0L)
    val networkChangeCount: StateFlow<Long> = _networkChangeCount.asStateFlow()

    /** 最近是否检测到网络丢失（60 秒窗口内） */
    private val _wasNetworkLostRecently = MutableStateFlow(false)
    val wasNetworkLostRecently: StateFlow<Boolean> = _wasNetworkLostRecently.asStateFlow()

    /** 最近一次网络丢失的时间戳（epoch ms），0 表示未丢失过 */
    @Volatile
    private var lastLossTimestamp: Long = 0L

    /** 待处理的失连标记：网络丢失后等待 Go 侧 onDisconnected 确认 */
    @Volatile
    private var pendingDisconnectFromLoss: Boolean = false

    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
        override fun onAvailable(network: Network) {
            Log.i(TAG, "Network available")
            _isAvailable.value = true
            _networkChangeCount.value += 1
        }

        override fun onLost(network: Network) {
            Log.w(TAG, "Network lost")
            _isAvailable.value = false
            _wasNetworkLostRecently.value = true
            lastLossTimestamp = System.currentTimeMillis()
            pendingDisconnectFromLoss = true
            _networkChangeCount.value += 1
        }

        override fun onCapabilitiesChanged(
            network: Network,
            capabilities: NetworkCapabilities,
        ) {
            val hasInternet = capabilities.hasCapability(
                NetworkCapabilities.NET_CAPABILITY_INTERNET
            )
            // 不修改 _isAvailable —— onCapabilitiesChanged 在移动网络下太频繁
            // （LTE↔5G 切换等），修改会导致 isAvailable collector 误触发重连。
            // 仅记录时间戳供 consumeNetworkLossDisconnect 在 Go idle timeout 兜底时判断。
            if (!hasInternet) {
                Log.d(TAG, "Network capabilities degraded: hasInternet=false")
                lastLossTimestamp = System.currentTimeMillis()
                pendingDisconnectFromLoss = true
            }
        }
    }

    /** 开始监听网络变化 */
    fun start() {
        try {
            connectivityManager.registerDefaultNetworkCallback(networkCallback)
            Log.i(TAG, "Network monitoring started")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to register network callback", e)
        }
    }

    /** 停止监听网络变化 */
    fun stop() {
        try {
            connectivityManager.unregisterNetworkCallback(networkCallback)
            Log.i(TAG, "Network monitoring stopped")
        } catch (e: Exception) {
            Log.e(TAG, "Failed to unregister network callback", e)
        }
    }

    /**
     * 在 onDisconnected 回调中调用，判断本次断线是否由网络丢失引起。
     *
     * 如果是网络丢失导致的断线，返回 true（应触发自动重连）；
     * 如果是服务器主动断线（如被踢、服务器关闭），返回 false。
     *
     * 此方法具有消耗性：调用后内部标志位被重置，重复调用返回 false。
     */
    fun consumeNetworkLossDisconnect(): Boolean {
        val wasRecent = _wasNetworkLostRecently.value ||
            (lastLossTimestamp > 0 &&
                System.currentTimeMillis() - lastLossTimestamp < RECENT_LOSS_WINDOW_MS)
        if (wasRecent && pendingDisconnectFromLoss) {
            pendingDisconnectFromLoss = false
            _wasNetworkLostRecently.value = false
            Log.i(TAG, "Consumed network-loss disconnect flag: wasRecent=$wasRecent")
            return true
        }
        Log.d(TAG, "consumeNetworkLossDisconnect: wasRecent=$wasRecent, pending=$pendingDisconnectFromLoss → false")
        return false
    }

    /**
     * 重置所有追踪状态。在以下场景调用：
     * - 用户主动断开连接
     * - 放弃重连
     * - 返回主页
     */
    fun reset() {
        pendingDisconnectFromLoss = false
        _wasNetworkLostRecently.value = false
        lastLossTimestamp = 0L
        Log.d(TAG, "Network loss tracking state reset")
    }
}
