package com.rosetta.messenger.network.connection

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkRequest
import android.os.Build
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class NetworkReconnectWatcher(
    private val scope: CoroutineScope,
    private val networkWaitTimeoutMs: Long,
    private val addLog: (String) -> Unit,
    private val onReconnectRequested: (String) -> Unit
) {
    private val lock = Any()

    @Volatile private var registered = false
    @Volatile private var callback: ConnectivityManager.NetworkCallback? = null
    @Volatile private var timeoutJob: Job? = null

    fun hasActiveInternet(context: Context?): Boolean {
        if (context == null) return true
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            ?: return true
        val network = cm.activeNetwork ?: return false
        val caps = cm.getNetworkCapabilities(network) ?: return false
        return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    }

    fun stop(context: Context?, reason: String? = null) {
        if (context == null) return
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            ?: return

        val currentCallback = synchronized(lock) {
            val current = callback
            callback = null
            registered = false
            timeoutJob?.cancel()
            timeoutJob = null
            current
        }

        if (currentCallback != null) {
            runCatching { cm.unregisterNetworkCallback(currentCallback) }
            if (!reason.isNullOrBlank()) {
                addLog("📡 NETWORK WATCH STOP: $reason")
            }
        }
    }

    fun waitForNetwork(context: Context?, reason: String) {
        if (context == null) return
        if (hasActiveInternet(context)) {
            stop(context, "network already available")
            return
        }

        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            ?: return

        val alreadyRegistered = synchronized(lock) {
            if (registered) {
                true
            } else {
                val callback =
                    object : ConnectivityManager.NetworkCallback() {
                        override fun onAvailable(network: Network) {
                            if (hasActiveInternet(context)) {
                                addLog("📡 NETWORK AVAILABLE → reconnect")
                                stop(context, "available")
                                onReconnectRequested("network_available")
                            }
                        }

                        override fun onCapabilitiesChanged(
                            network: Network,
                            networkCapabilities: NetworkCapabilities
                        ) {
                            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
                                addLog("📡 NETWORK CAPABILITIES READY → reconnect")
                                stop(context, "capabilities_changed")
                                onReconnectRequested("network_capabilities_changed")
                            }
                        }
                    }
                this.callback = callback
                registered = true
                false
            }
        }

        if (alreadyRegistered) {
            addLog("📡 NETWORK WAIT already active (reason=$reason)")
            return
        }

        addLog("📡 NETWORK WAIT start (reason=$reason)")
        runCatching {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                cm.registerDefaultNetworkCallback(callback!!)
            } else {
                val request =
                    NetworkRequest.Builder()
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .build()
                cm.registerNetworkCallback(request, callback!!)
            }
        }.onFailure { error ->
            addLog("⚠️ NETWORK WAIT register failed: ${error.message}")
            stop(context, "register_failed")
            onReconnectRequested("network_wait_register_failed")
        }

        timeoutJob?.cancel()
        timeoutJob =
            scope.launch {
                delay(networkWaitTimeoutMs)
                if (!hasActiveInternet(context)) {
                    addLog("⏱️ NETWORK WAIT timeout (${networkWaitTimeoutMs}ms), reconnect fallback")
                    stop(context, "timeout")
                    onReconnectRequested("network_wait_timeout")
                }
            }
    }
}
