package com.ponzischeme89.memby.data.remote

import okhttp3.ConnectionPool
import okhttp3.Dispatcher
import okhttp3.OkHttpClient
import java.util.concurrent.TimeUnit

/**
 * The one HTTP stack in the app. Everything that talks to the network — the Emby API, the
 * gateway API and Coil's artwork loader — is built from [base], so they share a single
 * connection pool, dispatcher and thread pool.
 *
 * Sharing matters most for artwork. In gateway mode the images are proxied by the same
 * HTTPS host that serves `/v1/home`, so a poster fetched on a client of its own would
 * open a fresh TCP connection and repeat the TLS handshake that the home request had just
 * finished — perhaps a couple of hundred milliseconds per cold image over a domestic
 * connection, multiplied by the fifteen-odd posters a launcher paints at once. Reusing
 * the pool makes those fetches resume an established connection instead.
 *
 * Timeouts and auth headers still differ per caller, so each factory calls
 * [base].newBuilder() and adds its own. That is the intended way to specialise an OkHttp
 * client: the derived client keeps the shared pool and dispatcher.
 */
internal object HttpStack {

    /**
     * A launcher paints far more than the default five concurrent requests per host, and
     * in gateway mode every one of them is the same host. Five means posters arrive in
     * visible waves; this lets a screenful start together while staying well short of
     * what would swamp a TV's radio.
     */
    private const val MAX_REQUESTS_PER_HOST = 15

    private val connectionPool = ConnectionPool(
        maxIdleConnections = 8,
        keepAliveDuration = 5,
        timeUnit = TimeUnit.MINUTES,
    )

    private val dispatcher = Dispatcher().apply {
        maxRequests = 32
        maxRequestsPerHost = MAX_REQUESTS_PER_HOST
    }

    val base: OkHttpClient = OkHttpClient.Builder()
        .connectionPool(connectionPool)
        .dispatcher(dispatcher)
        // Sensible floor; every caller overrides these to suit what it is fetching.
        .connectTimeout(15, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .retryOnConnectionFailure(true)
        .build()
}
