package de.trainingstagebuch.app.core

import android.content.Context
import androidx.annotation.StringRes
import de.trainingstagebuch.app.R
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import retrofit2.HttpException

enum class StandardErrorType {
    Network,
    Timeout,
    Client,
    Server,
    Unknown
}

data class StandardUiError(
    val type: StandardErrorType,
    val message: String,
    val httpCode: Int? = null
)

object StandardErrorMapper {
    @Volatile
    private var appContext: Context? = null

    fun initialize(context: Context) {
        appContext = context.applicationContext
    }

    private fun message(@StringRes resId: Int, vararg args: Any): String {
        val ctx = appContext
        return if (ctx != null) {
            ctx.getString(resId, *args)
        } else {
            // Fallback if called before initialize
            when (resId) {
                R.string.error_timeout -> "Timeout"
                R.string.error_no_network -> "No network"
                R.string.error_network -> "Network error"
                R.string.error_http_4xx -> "Client error"
                R.string.error_http_5xx -> "Server error"
                R.string.error_http_generic -> "HTTP error"
                else -> "Unknown error"
            }
        }
    }

    fun fromRes(@StringRes resId: Int, vararg args: Any): String = message(resId, *args)

    fun map(throwable: Throwable): StandardUiError {
        return when (throwable) {
            is SocketTimeoutException -> StandardUiError(
                type = StandardErrorType.Timeout,
                message = message(R.string.error_timeout)
            )

            is UnknownHostException -> StandardUiError(
                type = StandardErrorType.Network,
                message = message(R.string.error_no_network)
            )

            is IOException -> StandardUiError(
                type = StandardErrorType.Network,
                message = message(R.string.error_network)
            )

            is HttpException -> mapHttp(throwable.code())

            else -> StandardUiError(
                type = StandardErrorType.Unknown,
                message = throwable.message ?: message(R.string.error_unknown)
            )
        }
    }

    fun mapHttp(httpCode: Int): StandardUiError {
        return when (httpCode) {
            in 400..499 -> StandardUiError(
                type = StandardErrorType.Client,
                message = message(R.string.error_http_4xx, httpCode),
                httpCode = httpCode
            )

            in 500..599 -> StandardUiError(
                type = StandardErrorType.Server,
                message = message(R.string.error_http_5xx, httpCode),
                httpCode = httpCode
            )

            else -> StandardUiError(
                type = StandardErrorType.Unknown,
                message = message(R.string.error_http_generic, httpCode),
                httpCode = httpCode
            )
        }
    }
}
