package wang.yaojia.webterm.di

import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import okhttp3.ConnectionPool
import okhttp3.OkHttpClient
import wang.yaojia.webterm.tlsandroid.AndroidIdentityRepository
import wang.yaojia.webterm.tlsandroid.AndroidKeyStoreImporter
import wang.yaojia.webterm.tlsandroid.CertStore
import wang.yaojia.webterm.tlsandroid.EnrollmentRecordStore
import wang.yaojia.webterm.tlsandroid.IdentityCacheRefresher
import wang.yaojia.webterm.tlsandroid.IdentityRepository
import wang.yaojia.webterm.tlsandroid.TinkCertStore
import wang.yaojia.webterm.tlsandroid.TinkEnrollmentRecordStore
import javax.inject.Singleton

/**
 * mTLS device-identity boundary (A15 → A11): the AndroidKeyStore importer (the ONE non-exportable key
 * home), the Tink-AEAD-encrypted cert-chain store, and the [IdentityRepository] that ties them to the
 * shared client for no-relaunch rotation (`connectionPool.evictAll()`).
 *
 * The repository's constructor is I/O-free (SSL material is built from standard JCA; keystore/Tink I/O
 * is lazy). Per A11's KDoc, the FIRST identity touch (summary / mutation / first handshake) does
 * synchronous AndroidKeyStore + Tink work and MUST be triggered off `Dispatchers.Main` — that warm-up
 * is A21/A27's concern, not this wiring's.
 *
 * The repository is given an evict-only client that SHARES [NetworkModule]'s [ConnectionPool] (see the
 * cycle-break note there), so `evictAll()` drops the real transports' pooled/resumed connections
 * without this module depending on the shared client (which would reintroduce the cycle).
 */
@Module
@InstallIn(SingletonComponent::class)
public object TlsModule {

    @Provides
    @Singleton
    public fun provideKeyStoreImporter(): AndroidKeyStoreImporter = AndroidKeyStoreImporter()

    @Provides
    @Singleton
    public fun provideCertStore(@ApplicationContext context: Context): CertStore = TinkCertStore(context)

    /** The Tink-AEAD-encrypted enrollment record (deviceId + key alias) the zero-`.p12` renew path reads. */
    @Provides
    @Singleton
    public fun provideEnrollmentRecordStore(
        @ApplicationContext context: Context,
    ): EnrollmentRecordStore = TinkEnrollmentRecordStore(context)

    /**
     * The ONE mTLS device-identity repository, provided as the concrete type so BOTH the
     * [IdentityRepository] surface (import/rotate/remove/summary) and the narrow [IdentityCacheRefresher]
     * seam (B4 enroll cache-freshness) resolve to the SAME singleton instance.
     */
    @Provides
    @Singleton
    public fun provideAndroidIdentityRepository(
        importer: AndroidKeyStoreImporter,
        certStore: CertStore,
        connectionPool: ConnectionPool,
    ): AndroidIdentityRepository {
        // Evict-only client: no mTLS of its own, just the SHARED pool so remove()/rotate()/refresh's
        // `connectionPool.evictAll()` clears the connections the real transports pooled (R4/§8).
        val evictClient = OkHttpClient.Builder().connectionPool(connectionPool).build()
        return AndroidIdentityRepository(importer, certStore, evictClient)
    }

    @Provides
    @Singleton
    public fun provideIdentityRepository(repository: AndroidIdentityRepository): IdentityRepository = repository

    /** FIX 3: the enroll/renew commit refreshes THIS same repository's in-memory cache (no restart). */
    @Provides
    @Singleton
    public fun provideIdentityCacheRefresher(repository: AndroidIdentityRepository): IdentityCacheRefresher =
        repository
}
