package wang.yaojia.webterm.wiring

import dagger.Lazy
import okhttp3.OkHttpClient
import wang.yaojia.webterm.api.enroll.DeviceEnrollmentClient
import wang.yaojia.webterm.tlsandroid.CertStore
import wang.yaojia.webterm.tlsandroid.DeviceEnroller
import wang.yaojia.webterm.tlsandroid.EnrollmentRecordStore
import wang.yaojia.webterm.tlsandroid.IdentityCacheRefresher
import wang.yaojia.webterm.wire.HttpTransport
import javax.inject.Inject
import javax.inject.Singleton

/**
 * B4 · Builds a [DeviceEnroller] bound to a user-supplied control-plane URL, over the app's frozen object
 * graph — the Android analogue of iOS `makeDeviceEnrollmentFlow` (`DeviceEnrollmentWiring.swift`).
 *
 * The control-plane base URL is a RUNTIME value (the operator types it on the enrollment screen), so the
 * enroller cannot be a plain singleton; this factory is the singleton and mints one enroller per enroll
 * attempt with the typed URL, wiring in the app-scoped collaborators:
 *  - the SAME shared [HttpTransport] / [OkHttpClient] the mTLS transports use, so the renew ride presents
 *    the current device cert and the pool eviction drops stale connections,
 *  - the shared [CertStore] + [EnrollmentRecordStore] the running [IdentityRepository] resolves from, and
 *  - the [IdentityCacheRefresher] (FIX 3) so a freshly enrolled leaf is presented with no restart.
 *
 * ### Off-`Main` discipline
 * [httpTransport] and [sharedClient] are behind `dagger.Lazy` because resolving either builds the shared
 * `OkHttpClient` (mTLS/keystore I/O). [create] therefore MUST be called off the UI thread — the enrollment
 * ViewModel invokes it inside a `Dispatchers.IO` hop (mirroring `AppEnvironment.warmUp`).
 */
@Singleton
public class EnrollmentFlowFactory @Inject constructor(
    private val httpTransport: Lazy<HttpTransport>,
    private val sharedClient: Lazy<OkHttpClient>,
    private val certStore: CertStore,
    private val recordStore: EnrollmentRecordStore,
    private val cacheRefresher: IdentityCacheRefresher,
) {
    /**
     * Mint a [DeviceEnroller] targeting [controlPlaneBaseUrl] (any trailing slash is trimmed by the
     * client). Call OFF `Main` — resolving the lazy transport/client does keystore/TLS I/O.
     */
    public fun create(controlPlaneBaseUrl: String): DeviceEnroller =
        DeviceEnroller(
            client = DeviceEnrollmentClient(controlPlaneBaseUrl, httpTransport.get()),
            certStore = certStore,
            recordStore = recordStore,
            sharedClient = sharedClient.get(),
            cacheRefresher = cacheRefresher,
        )
}
