package de.tsschulz.tt_tagebuch.shared.api.http

import de.tsschulz.tt_tagebuch.shared.api.ApiConfig
import de.tsschulz.tt_tagebuch.shared.state.TokenProvider
import io.ktor.client.HttpClient
import io.ktor.client.plugins.DefaultRequest
import io.ktor.client.plugins.HttpResponseValidator
import io.ktor.client.plugins.HttpTimeout
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
import io.ktor.client.request.header
import io.ktor.client.request.url
import io.ktor.http.ContentType
import io.ktor.http.contentType
import io.ktor.serialization.kotlinx.json.json
import kotlinx.serialization.json.Json

class AuthedHttpClient(
    apiConfig: ApiConfig,
    private val tokenProvider: TokenProvider,
    httpClientEngineFactory: HttpClientEngineFactory,
    private val onUnauthorized: () -> Unit = {},
) {
    val http: HttpClient = HttpClient(httpClientEngineFactory.create()) {
        install(ContentNegotiation) {
            json(
                Json {
                    ignoreUnknownKeys = true
                    coerceInputValues = true
                }
            )
        }
        install(HttpTimeout) {
            requestTimeoutMillis = 60_000
            connectTimeoutMillis = 15_000
            socketTimeoutMillis = 60_000
        }
        HttpResponseValidator {
            validateResponse { response ->
                val statusCode = response.status.value
                if (statusCode == 401) {
                    onUnauthorized()
                    val detail = response.userFacingErrorOr("Session abgelaufen")
                    throw ApiException(statusCode, detail)
                }
                if (statusCode >= 400) {
                    val detail = response.userFacingErrorOr("API Fehler $statusCode")
                    throw ApiException(statusCode, detail)
                }
            }
        }
        install(DefaultRequest) {
            url(apiConfig.baseUrl)
            contentType(ContentType.Application.Json)
            tokenProvider.token?.let { token ->
                header("authcode", token)
            }
            tokenProvider.username?.let { username ->
                header("userid", username)
            }
        }
    }
}
