package com.fabledsword.minstrel.api

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import retrofit2.HttpException
import java.io.IOException

/**
 * Maps server error codes (and common transport failures) to
 * friendly, sentence-case copy. Mirrors
 * `flutter_client/assets/error-copy.json` + `error_copy.dart`.
 *
 * Server errors are `{"error":{"code":"...","message":"..."}}`.
 * [fromThrowable] pulls the code out of a Retrofit [HttpException]'s
 * error body and maps it; network failures (no connection / DNS /
 * refused) map to `connection_refused`; anything unrecognised falls
 * back to `unknown`.
 *
 * Replaces the `e.message ?: "unknown error"` pattern scattered
 * across ViewModels with copy a user can actually act on.
 */
object ErrorCopy {
    private val json = Json { ignoreUnknownKeys = true }

    @Serializable
    private data class Envelope(val error: Body? = null)

    @Serializable
    private data class Body(val code: String = "", val message: String = "")

    /** Friendly copy for a known error [code], or the `unknown` fallback. */
    fun messageFor(code: String): String = TABLE[code] ?: TABLE.getValue("unknown")

    /**
     * Friendly copy for any caught throwable. Parses Retrofit
     * HttpException bodies for the server code; treats IOExceptions
     * as connection failures.
     */
    fun fromThrowable(t: Throwable): String = when (t) {
        is HttpException -> messageFor(codeFromHttp(t))
        is IOException -> messageFor("connection_refused")
        else -> TABLE.getValue("unknown")
    }

    private fun codeFromHttp(e: HttpException): String {
        val raw = runCatching { e.response()?.errorBody()?.string() }.getOrNull()
            ?: return "unknown"
        val code = runCatching { json.decodeFromString<Envelope>(raw).error?.code }
            .getOrNull()
            .orEmpty()
        return code.ifEmpty { "unknown" }
    }

    private val TABLE: Map<String, String> = mapOf(
        "unknown" to "Something went wrong.",
        "unauthenticated" to "Your session has ended. Please sign in again.",
        "auth_required" to "You need to sign in to do that.",
        "forbidden" to "You don't have permission to do that.",
        "not_authorized" to "You don't have permission to do that.",
        "invalid_credentials" to "Wrong username or password.",
        "wrong_password" to "Current password is incorrect.",
        "password_too_short" to "Password must be at least 8 characters.",
        "username_invalid" to "That username isn't valid.",
        "username_taken" to "That username is already taken.",
        "email_invalid" to "Enter a valid email address.",
        "email_taken" to "That email is already in use.",
        "invalid_token" to "That link has expired or already been used. Request a new one.",
        "invite_invalid" to "That invite has expired or already been used.",
        "invite_required" to "An invite is required to register on this server.",
        "last_admin" to "Can't demote or delete the last admin.",
        "no_email_on_file" to "No email is associated with that account.",
        "not_configured" to "This integration isn't set up yet.",
        "validation" to "Some fields aren't valid. Check and try again.",
        "missing_fields" to "Required fields are missing.",
        "missing_query" to "Search needs at least one keyword.",
        "invalid_id" to "Invalid identifier.",
        "invalid_body" to "Couldn't read the request.",
        "bad_request" to "Invalid request.",
        "bad_body" to "Couldn't read the request.",
        "bad_kind" to "Invalid request type.",
        "bad_paging" to "Invalid page size or offset.",
        "bad_reason" to "Invalid quarantine reason.",
        "mbid_required" to "An MBID is required for this lookup.",
        "system_playlist_readonly" to "System playlists can't be edited directly.",
        "connection_refused" to "Couldn't reach the server. Check the URL and try again.",
        "lidarr_unreachable" to
            "Lidarr is unreachable right now. Try again, or check Admin → Integrations.",
        "lidarr_disabled" to "Lidarr integration is not enabled.",
        "lidarr_auth_failed" to "Lidarr authentication failed.",
        "lidarr_defaults_incomplete" to
            "Lidarr is missing a default quality profile or root folder. " +
            "Set them in Admin → Integrations.",
        "lidarr_server_error" to "Lidarr returned an error. Check Lidarr's logs for the cause.",
        "lidarr_rejected" to
            "Lidarr rejected the request. Check the server logs for the field-level reason.",
        "lidarr_album_lookup_failed" to
            "Lidarr doesn't recognize this album. Try Resolve or Delete file instead.",
        "album_mbid_missing" to "This track has no Lidarr album to remove.",
        "request_not_pending" to "This request is no longer pending.",
        "request_not_found" to "That request no longer exists.",
        "track_not_found" to "That track no longer exists.",
        "album_not_found" to "That album no longer exists.",
        "artist_not_found" to "That artist no longer exists.",
        "playlist_not_found" to "That playlist no longer exists.",
        "user_not_found" to "That user no longer exists.",
        "not_found" to "That no longer exists.",
    )
}
