package wang.yaojia.webterm.hostregistry

import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import wang.yaojia.webterm.wire.HostEndpoint

/**
 * [HostCodec] is the pure at-rest (de)serializer the DataStore store delegates to.
 * Host records are UNTRUSTED at rest: the codec must round-trip cleanly, re-derive
 * the endpoint via [HostEndpoint.fromBaseUrl], drop records whose baseUrl no longer
 * validates, and never crash on a corrupt blob.
 */
class HostCodecTest {

    private fun host(id: String, name: String, baseUrl: String, hasCert: Boolean = false): Host =
        Host(id = id, name = name, endpoint = requireNotNull(HostEndpoint.fromBaseUrl(baseUrl)), hasDeviceCert = hasCert)

    @Test
    fun `encode then decode round-trips id, name, endpoint and cert flag`() {
        val hosts = listOf(
            host("1", "mac", "http://192.168.1.5:3000", hasCert = true),
            host("2", "tailnet", "https://mac.tailnet.ts.net"),
        )

        val restored = HostCodec.decode(HostCodec.encode(hosts))

        assertEquals(hosts, restored)
        // The endpoint is RE-DERIVED, not stored — verify the derivations survived.
        assertEquals("wss://mac.tailnet.ts.net/term", restored[1].endpoint.wsUrl)
        assertEquals(true, restored[0].hasDeviceCert)
    }

    @Test
    fun `decode drops a record whose stored baseUrl no longer validates`() {
        // A hand-written blob with one good and one malformed baseUrl (untrusted at rest).
        val raw = """
            [
              {"id":"1","name":"good","baseUrl":"http://10.0.0.1:3000","hasDeviceCert":false},
              {"id":"2","name":"bad","baseUrl":"not a url","hasDeviceCert":false}
            ]
        """.trimIndent()

        val restored = HostCodec.decode(raw)

        assertEquals(1, restored.size)
        assertEquals("1", restored.single().id)
    }

    @Test
    fun `decode of a corrupt or blank blob yields an empty list, never throws`() {
        assertTrue(HostCodec.decode(null).isEmpty())
        assertTrue(HostCodec.decode("").isEmpty())
        assertTrue(HostCodec.decode("   ").isEmpty())
        assertTrue(HostCodec.decode("{not json").isEmpty())
    }

    @Test
    fun `decode preserves stored order`() {
        val hosts = listOf(
            host("a", "first", "http://10.0.0.1:3000"),
            host("b", "second", "http://10.0.0.2:3000"),
            host("c", "third", "http://10.0.0.3:3000"),
        )

        val restored = HostCodec.decode(HostCodec.encode(hosts))

        assertEquals(listOf("a", "b", "c"), restored.map { it.id })
    }
}
