package com.tt.honeyDue.network

import coil3.intercept.Interceptor
import coil3.network.HttpException
import coil3.network.httpHeaders
import coil3.request.ErrorResult
import coil3.request.ImageResult

/**
 * Coil3 [Interceptor] that attaches an `Authorization` header to every
 * outgoing image request and, on an HTTP 401 response, refreshes the token
 * and retries exactly once.
 *
 * Mirrors the behavior of the iOS `AuthenticatedImage` in
 * `iosApp/iosApp/Components/AuthenticatedImage.swift`, centralising the
 * concern so individual composables don't need to thread the token through
 * themselves.
 *
 * Usage — install on the singleton [coil3.ImageLoader]:
 * ```kotlin
 * ImageLoader.Builder(context)
 *     .components {
 *         add(CoilAuthInterceptor(
 *             tokenProvider = { TokenStorage.getToken() },
 *             refreshToken = { (APILayer.refreshToken() as? ApiResult.Success)?.data },
 *             authScheme = "Token",
 *         ))
 *         add(KtorNetworkFetcherFactory())
 *     }
 *     .build()
 * ```
 *
 * @param tokenProvider Suspending supplier of the current auth token. Returning
 *   `null` means "no token available" — the request proceeds unauthenticated.
 * @param refreshToken Suspending supplier that refreshes the backing session and
 *   returns a fresh token, or `null` if refresh failed.
 * @param authScheme The auth scheme to prefix the token with (default `Token`
 *   to match the existing Go backend — use `Bearer` for JWT deployments).
 */
class CoilAuthInterceptor(
    private val tokenProvider: suspend () -> String?,
    private val refreshToken: suspend () -> String?,
    private val authScheme: String = "Token",
) : Interceptor {

    override suspend fun intercept(chain: Interceptor.Chain): ImageResult {
        val token = tokenProvider()

        // No token — proceed without adding the header so anonymous
        // endpoints still work.
        if (token == null) {
            return chain.proceed()
        }

        val authed = chain.request.newBuilder()
            .httpHeaders(
                chain.request.httpHeaders.newBuilder()
                    .set(HEADER_AUTHORIZATION, "$authScheme $token")
                    .build()
            )
            .build()

        val result = chain.withRequest(authed).proceed()

        // If the server rejected the token, try refreshing once.
        if (result.isUnauthorized()) {
            val newToken = refreshToken() ?: return result
            val retried = authed.newBuilder()
                .httpHeaders(
                    authed.httpHeaders.newBuilder()
                        .set(HEADER_AUTHORIZATION, "$authScheme $newToken")
                        .build()
                )
                .build()
            // Only retry *once* — whatever comes back from this call is final,
            // even if it is itself a 401. This guards against an infinite loop
            // when refresh succeeds but the backing account is still revoked.
            return chain.withRequest(retried).proceed()
        }

        return result
    }

    private fun ImageResult.isUnauthorized(): Boolean {
        if (this !is ErrorResult) return false
        val ex = throwable as? HttpException ?: return false
        return ex.response.code == HTTP_UNAUTHORIZED
    }

    companion object {
        private const val HEADER_AUTHORIZATION = "Authorization"
        private const val HTTP_UNAUTHORIZED = 401
    }
}
