package com.horrortv.app.util

import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities

import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NetworkStatus @Inject constructor(
    private val context: Context
) {
    
    private val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    
    fun isNetworkAvailable(): Boolean {
        val network = connectivityManager.activeNetwork ?: return false
        val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
               capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) &&
               (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN) ||
                capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
    }
    
    fun isMeteredNetwork(): Boolean {
        val network = connectivityManager.activeNetwork ?: return false
        val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
    }
    
    fun isWifi(): Boolean {
        val network = connectivityManager.activeNetwork ?: return false
        val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
    }
    
    fun observeNetworkStatus(): Flow<NetworkState> = callbackFlow {
        val callback = object : ConnectivityManager.NetworkCallback() {
            override fun onAvailable(network: Network) {
                // Don't emit here — wait for onCapabilitiesChanged which has full state
            }

            override fun onCapabilitiesChanged(network: Network, capabilities: NetworkCapabilities) {
                val hasInternet = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                val validated = capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                val wifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                val cellular = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                val vpn = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
                val metered = !capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)

                if (hasInternet && validated) {
                    trySend(NetworkState.Available(wifi = wifi, metered = metered))
                } else {
                    trySend(NetworkState.Unavailable)
                }
            }

            override fun onLost(network: Network) {
                // Check if there's still another active network
                val activeNetwork = connectivityManager.activeNetworkInfo?.isConnectedOrConnecting == true
                if (!activeNetwork) {
                    trySend(NetworkState.Unavailable)
                }
            }
        }

        connectivityManager.registerDefaultNetworkCallback(callback)

        trySend(if (isNetworkAvailable()) NetworkState.Available() else NetworkState.Unavailable)

        awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
    }.distinctUntilChanged()
    
    sealed class NetworkState {
        object Unavailable : NetworkState()
        data class Available(val metered: Boolean = false, val wifi: Boolean = false) : NetworkState()
    }
}