package com.optix.android.util

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.wifi.WifiManager
import androidx.core.content.ContextCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import java.net.Inet4Address
import java.net.NetworkInterface
import java.util.Collections
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NetworkUtils @Inject constructor(
    @ApplicationContext private val context: Context,
) {

    data class NetworkState(
        val ipAddress: String? = null,
        val prefixLength: Int = 24,
        val subnet: String? = null,
        val gatewayIp: String? = null,
        val isWifiConnected: Boolean = false,
        val connectedSsid: String? = null,
    )

    data class WifiAccessPoint(
        val ssid: String,
        val bssid: String?,
        val signalLevelDbm: Int,
        val security: String,
        val isConnected: Boolean,
    )

    fun getLocalNetworkState(): NetworkState {
        val isWifiConnected = isWifiTransportActive()
        val connectedSsid = getConnectedWifiSsid()
        try {
            val interfaces = Collections.list(NetworkInterface.getNetworkInterfaces())
            for (intf in interfaces) {
                if (!intf.isUp || intf.isLoopback) continue

                for (addr in intf.interfaceAddresses) {
                    val inetAddress = addr.address
                    if (inetAddress is Inet4Address) {
                        val ip = inetAddress.hostAddress ?: continue
                        val prefix = addr.networkPrefixLength.toInt()
                        val subnet = calculateSubnet(ip, prefix)
                        val gateway = guessGateway(ip, prefix)
                        return NetworkState(
                            ipAddress = ip,
                            prefixLength = prefix,
                            subnet = subnet,
                            gatewayIp = gateway,
                            isWifiConnected = isWifiConnected,
                            connectedSsid = connectedSsid,
                        )
                    }
                }
            }
        } catch (_: Exception) {
        }
        return NetworkState(
            isWifiConnected = isWifiConnected,
            connectedSsid = connectedSsid,
        )
    }

    fun scanNearbyWifiNetworks(): List<WifiAccessPoint> {
        if (!hasWifiScanPermission()) return emptyList()
        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
            ?: return emptyList()
        val connectedSsid = getConnectedWifiSsid()

        return runCatching {
            @Suppress("DEPRECATION")
            wifiManager.scanResults.orEmpty()
                .mapNotNull { ap ->
                    @Suppress("DEPRECATION")
                    val ssid = ap.SSID?.takeIf { it.isNotBlank() } ?: return@mapNotNull null
                    WifiAccessPoint(
                        ssid = ssid,
                        bssid = ap.BSSID,
                        signalLevelDbm = ap.level,
                        security = ap.capabilities?.ifBlank { "Unknown" } ?: "Unknown",
                        isConnected = connectedSsid != null && normalizeSsid(connectedSsid) == normalizeSsid(ssid),
                    )
                }
                .distinctBy { "${it.ssid}|${it.bssid}" }
                .sortedByDescending { it.signalLevelDbm }
        }.getOrElse { emptyList() }
    }

    fun hasWifiScanPermission(): Boolean {
        return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
            ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
    }

    private fun isWifiTransportActive(): Boolean {
        val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
            ?: return false
        val network = connectivityManager.activeNetwork ?: return false
        val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
        return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
    }

    private fun getConnectedWifiSsid(): String? {
        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as? WifiManager
            ?: return null
        return runCatching {
            @Suppress("DEPRECATION")
            normalizeSsid(wifiManager.connectionInfo?.ssid)
        }.getOrNull()
    }

    private fun normalizeSsid(raw: String?): String? {
        return raw
            ?.trim()
            ?.removePrefix("\"")
            ?.removeSuffix("\"")
            ?.takeIf { it.isNotBlank() && it != "<unknown ssid>" }
    }

    private fun guessGateway(ip: String, prefix: Int): String? {
        val parts = ip.split(".")
        if (parts.size != 4) return null
        return when {
            prefix >= 24 -> "${parts[0]}.${parts[1]}.${parts[2]}.1"
            prefix >= 16 -> "${parts[0]}.${parts[1]}.1.1"
            else -> null
        }
    }

    private fun calculateSubnet(ip: String, prefix: Int): String {
        val parts = ip.split(".")
        if (parts.size != 4) return "192.168.1.0/$prefix"

        return when (prefix) {
            in 24..31 -> "${parts[0]}.${parts[1]}.${parts[2]}.0/$prefix"
            in 16..23 -> "${parts[0]}.${parts[1]}.0.0/$prefix"
            in 8..15 -> "${parts[0]}.0.0.0/$prefix"
            else -> "$ip/$prefix"
        }
    }
}
