package com.ledgrab.android

import android.content.Context
import android.net.ConnectivityManager
import android.net.LinkProperties
import android.net.Network
import android.net.NetworkCapabilities
import java.net.Inet4Address

/**
 * Network utilities for discovering the device's local IP address.
 */
object NetworkUtils {

    /**
     * Return the device's local IPv4 address, preferring (in order):
     *  - Ethernet (wired TV-box link)
     *  - Wi-Fi
     *  - any other transport
     *  - whatever the active network reports
     *
     * Returns ``null`` only when no IPv4 link addresses exist at all.
     *
     * Why not just ``activeNetwork``: on TV boxes with both Ethernet
     * AND Wi-Fi connected, Android's active-network heuristic can
     * pick Wi-Fi while the user's phone is on the Ethernet subnet —
     * leading to a URL/QR that the phone can't reach.
     */
    fun getLocalIpAddress(context: Context): String? {
        val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        // TODO(AP-mode): On TV boxes acting as a Wi-Fi tether/hotspot,
        // TRANSPORT_WIFI here will resolve to the AP-side interface
        // (typically 192.168.43.x) which clients on the user's actual
        // home LAN can't reach. Detecting AP mode requires the @SystemApi
        // WifiManager.getWifiApState reflection trick — defer until a
        // user reports needing it.
        val networks = cm.allNetworks
        if (networks.isEmpty()) return ipv4Of(cm, cm.activeNetwork ?: return null)

        val ranked = networks
            .mapNotNull { n ->
                val caps = cm.getNetworkCapabilities(n) ?: return@mapNotNull null
                val rank = when {
                    caps.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> 0
                    caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> 1
                    caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) -> 3
                    caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> 4
                    else -> 2
                }
                Triple(rank, n, caps)
            }
            .sortedBy { it.first }

        for ((_, network, _) in ranked) {
            val ip = ipv4Of(cm, network)
            if (ip != null) return ip
        }
        return null
    }

    private fun ipv4Of(cm: ConnectivityManager, network: Network): String? {
        val props: LinkProperties = cm.getLinkProperties(network) ?: return null
        return props.linkAddresses
            .asSequence()
            .map { it.address }
            .filterIsInstance<Inet4Address>()
            .firstOrNull { !it.isLoopbackAddress && !it.isLinkLocalAddress }
            ?.hostAddress
    }
}
