package wang.yaojia.webterm.transport

import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Assertions.assertSame
import org.junit.jupiter.api.Test
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManagerFactory
import javax.net.ssl.X509TrustManager
import java.security.KeyStore

/**
 * The shared-client invariants (plan §8): NO HTTP cache (preview/diff bodies can hold terminal
 * secrets), and injected mTLS material is actually wired onto the client.
 */
class OkHttpClientFactoryTest {

    @Test
    fun sharedClientHasNoCache() {
        val client = OkHttpClientFactory.create()
        assertNull(client.cache, "OkHttpClient.cache must be null — no terminal secrets on disk")
    }

    @Test
    fun defaultProviderInstallsNoClientIdentityButStillBuilds() {
        val client = OkHttpClientFactory.create(ClientIdentityProvider.NONE)
        assertNotNull(client.sslSocketFactory) // default system factory, not a caller-supplied one
    }

    @Test
    fun injectedIdentityIsAppliedToTheClient() {
        // Arrange: a system-default trust manager + matching socket factory as stand-in mTLS material.
        val trustManager = systemDefaultTrustManager()
        val sslSocketFactory = SSLContext.getInstance("TLS")
            .apply { init(null, arrayOf(trustManager), null) }
            .socketFactory

        // Act
        val client = OkHttpClientFactory.create { ClientIdentity(sslSocketFactory, trustManager) }

        // Assert: the shared client uses exactly the injected factory (mTLS applies to WS + REST).
        assertSame(sslSocketFactory, client.sslSocketFactory)
    }

    @Test
    fun composesBothTransportsFromOneClientWithNoCache() {
        val transports = OkHttpTransports.create()
        assertNotNull(transports.term)
        assertNotNull(transports.http)
        assertNull(transports.client.cache)
    }

    private fun systemDefaultTrustManager(): X509TrustManager {
        val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
        factory.init(null as KeyStore?)
        return factory.trustManagers.filterIsInstance<X509TrustManager>().first()
    }
}
