package no.svorka.mcms.core

import kotlinx.serialization.json.JsonElement

/** Typed errors surfaced by [ApiClient]. */
sealed class ApiError(message: String) : Exception(message) {
    data object InvalidUrl : ApiError("The request URL was invalid.")
    data class Transport(val detail: String) : ApiError("Network error: $detail")
    data object ServerTrust : ApiError("The server's TLS certificate could not be trusted.")
    data class Encoding(val detail: String) : ApiError("Failed to encode request: $detail")
    data class Decoding(val detail: String) : ApiError("Failed to read server response: $detail")

    data class BadRequest(val details: JsonElement?) : ApiError("Request rejected (400). ${details.compactDescription()}")
    data object Unauthorized : ApiError("Not authenticated (401). Please sign in again.")
    data class Forbidden(val details: JsonElement?) : ApiError("Forbidden (403) — your account may not have permission for this action. ${details.compactDescription()}")
    data object NotFound : ApiError("Resource not found (404).")
    data class Conflict(val details: JsonElement?) : ApiError("Conflict (409) — ID already in use. ${details.compactDescription()}")
    data object UnsupportedMediaType : ApiError("Unsupported media type (415).")
    data class Server(val details: JsonElement?) : ApiError("Server error (500). ${details.compactDescription()}")
    data class ApiFailure(val details: JsonElement?) : ApiError("Request failed. ${details.compactDescription()}")
    data class UnexpectedStatus(val code: Int, val details: JsonElement?) : ApiError("Unexpected response ($code). ${details.compactDescription()}")

    /** Only 401 should bounce to login; a 403 is usually a permission/CSRF issue. */
    val requiresReauthentication: Boolean get() = this is Unauthorized

    companion object {
        fun fromStatus(code: Int, details: JsonElement?): ApiError = when (code) {
            400 -> BadRequest(details)
            401 -> Unauthorized
            403 -> Forbidden(details)
            404 -> NotFound
            409 -> Conflict(details)
            415 -> UnsupportedMediaType
            500 -> Server(details)
            else -> UnexpectedStatus(code, details)
        }
    }
}
