package wang.yaojia.webterm.clienttls

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
import wang.yaojia.webterm.wire.HostClassifier
import wang.yaojia.webterm.wire.HostEndpoint
import wang.yaojia.webterm.wire.HostNetworkTier

/** Ports iOS `HostClassificationTests` — the four §5.4 warning tiers + the fail-safe default. */
class HostClassifierTest {
    @Test
    fun loopbackTierMatchesLocalTargets() {
        val hosts = listOf("localhost", "LOCALHOST", "127.0.0.1", "127.8.8.8", "::1", "[::1]")
        for (host in hosts) {
            assertEquals(HostNetworkTier.LOOPBACK, HostClassifier.classify(host), "$host should be loopback")
        }
    }

    @Test
    fun privateLanTierMatchesRfc1918AndLinkLocal() {
        val hosts = listOf(
            "10.0.0.5", "192.168.0.9", "172.16.0.1", "172.31.255.255",
            "169.254.1.1", "mac-mini.local", "Mac-Mini.LOCAL",
        )
        for (host in hosts) {
            assertEquals(HostNetworkTier.PRIVATE_LAN, HostClassifier.classify(host), "$host should be privateLAN")
        }
    }

    @Test
    fun tailscaleTierMatchesCgnatAndMagicDns() {
        val hosts = listOf(
            "100.64.0.1", "100.100.1.1", "100.127.255.255",
            "mac.tailnet.ts.net", "foo.TS.NET",
        )
        for (host in hosts) {
            assertEquals(HostNetworkTier.TAILSCALE, HostClassifier.classify(host), "$host should be tailscale")
        }
    }

    @Test
    fun publicTierIsTheFailSafeDefault() {
        // Out of range: 172.32 exceeds 172.16/12; 100.128 & 100.63 exceed 100.64/10; malformed IPv4.
        val hosts = listOf(
            "8.8.8.8", "203.0.113.7", "example.com", "tsnet.example.com",
            "172.32.0.1", "100.128.0.1", "100.63.255.255", "256.1.1.1", "1.2.3", "",
        )
        for (host in hosts) {
            assertEquals(HostNetworkTier.PUBLIC, HostClassifier.classify(host), "$host should be public")
        }
    }

    @Test
    fun classifyEndpointMatchesHostStringVersion() {
        val vectors = listOf(
            "http://127.0.0.1:3000" to HostNetworkTier.LOOPBACK,
            "http://192.168.1.5:3000" to HostNetworkTier.PRIVATE_LAN,
            "http://100.100.1.1:3000" to HostNetworkTier.TAILSCALE,
            "https://mac.tailnet.ts.net" to HostNetworkTier.TAILSCALE,
            "https://example.com" to HostNetworkTier.PUBLIC,
        )
        for ((url, tier) in vectors) {
            val endpoint = requireNotNull(HostEndpoint.fromBaseUrl(url)) { "endpoint for $url" }
            assertEquals(tier, HostClassifier.classify(endpoint), url)
        }
    }

    @Test
    fun ipv4OctetsStrictParseRejectsNonDottedQuads() {
        assertNull(HostClassifier.ipv4Octets(""))
        assertNull(HostClassifier.ipv4Octets("1.2.3"))
        assertNull(HostClassifier.ipv4Octets("1.2.3.4.5"))
        assertNull(HostClassifier.ipv4Octets("256.1.1.1"))
        assertNull(HostClassifier.ipv4Octets("-1.2.3.4"))
        assertNull(HostClassifier.ipv4Octets("a.b.c.d"))
        assertNull(HostClassifier.ipv4Octets(".1.2.3"))
        assertEquals(listOf(10, 0, 0, 255), HostClassifier.ipv4Octets("10.0.0.255")?.toList())
    }
}
