/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.ui.shard

import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonObject

/**
 * One-line human descriptions of shard events for the live activity feed
 * (PLAN.md §6.2). Mirrors the website's `lib/shardEvents.js` `describe()` for the
 * public-safe kinds, so the app reads the same as the site. Accepts the event
 * fields as a [JsonObject] — the live SSE frame carries them at the top level;
 * a stored feed row carries them under `payload` (unwrap before calling).
 */
object ShardEventText {

    fun describe(kind: String, fields: JsonObject): String = when (kind) {
        "player.death" ->
            "${nameOf(fields["who"])} was slain" + fields["killer"].let { if (isPresent(it)) " by ${nameOf(it)}" else "" }
        "player.murdered" ->
            "${nameOf(fields["victim"])} was murdered" + fields["murderer"].let { if (isPresent(it)) " by ${nameOf(it)}" else "" }
        "mob.killed" -> "${nameOf(fields["killer"])} killed ${nameOf(fields["killed"])}"
        "skill.gain" -> "${nameOf(fields["who"])} gained ${str(fields["skill"])}".trim()
        "fame.change" -> "${nameOf(fields["who"])}’s fame changed to ${num(fields["new"])}"
        "karma.change" -> "${nameOf(fields["who"])}’s karma changed to ${num(fields["new"])}"
        "quest.complete" -> "${nameOf(fields["who"])} completed “${str(fields["quest"])}”"
        "house.decay" -> {
            val name = str(fields["name"]).ifBlank { "A house" }
            val stage = str(fields["to"]).ifBlank { str(fields["stage"]) }
            val region = str(fields["region"])
            "$name is now $stage" + if (region.isNotBlank()) " — $region" else ""
        }
        "mob.login" -> "${nameOf(fields["who"])} entered the world"
        "mob.logout" -> "${nameOf(fields["who"])} left the world"
        "economy.supply" -> "Gold supply: ${num(fields["gold"])} across ${num(fields["accounts"])} accounts"
        "server.hello" -> "Shard online — ${num(fields["accounts"])} accounts, ${num(fields["mobiles"])} mobiles"
        "server.shutdown" -> "Shard shut down"
        "server.crashed" -> "Shard crashed" + str(fields["error"]).let { if (it.isNotBlank()) ": $it" else "" }
        "champ.update" -> {
            val where = str(fields["name"]).ifBlank { str(fields["type"]).ifBlank { "A champion spawn" } }
            when {
                str(fields["status"]) == "active" && bool(fields["bossUp"]) ->
                    "$where: boss is up" + str(fields["boss"]).let { if (it.isNotBlank()) " ($it)" else "" }
                str(fields["status"]) == "active" -> "$where is active"
                str(fields["status"]) == "cooldown" -> "$where is on cooldown"
                else -> "$where is ${str(fields["status"]).ifBlank { "idle" }}"
            }
        }
        "champ.remove" -> "A champion spawn ended"
        "guild.update" -> "${str(fields["name"]).ifBlank { "A guild" }} updated"
        "guild.remove" -> "A guild disbanded"
        "guild.join" -> "${nameOf(fields["who"])} joined ${str(fields["guild"]).ifBlank { "a guild" }}".trim()
        "city.update" -> {
            val gov = fields["governor"]
            if (isPresent(gov)) "${str(fields["city"])} is governed by ${nameOf(gov)}"
            else "${str(fields["city"])} has no governor"
        }
        "presence.online" -> "${num(fields["count"])} players online"
        "region.enter" -> "${nameOf(fields["who"])} entered ${str(fields["region"]).ifBlank { "a region" }}".trim()
        else -> kind
    }

    // ── field helpers ─────────────────────────────────────────────────────
    private fun isPresent(el: JsonElement?): Boolean = el != null && el !is JsonNull

    /** Name of an actor that may be a bare string or a `{ name, acct }` object. */
    private fun nameOf(el: JsonElement?): String {
        if (!isPresent(el)) return "Someone"
        if (el is JsonPrimitive) return el.content.ifBlank { "Someone" }
        val obj = runCatching { el!!.jsonObject }.getOrNull() ?: return "Someone"
        return str(obj["name"]).ifBlank { str(obj["acct"]).ifBlank { "Someone" } }
    }

    private fun str(el: JsonElement?): String =
        if (el is JsonPrimitive && el !is JsonNull) el.content else ""

    private fun bool(el: JsonElement?): Boolean =
        el is JsonPrimitive && el.content.equals("true", ignoreCase = true)

    /** Format a numeric field with thousands grouping; falls back to its raw text. */
    private fun num(el: JsonElement?): String {
        val raw = str(el)
        val d = raw.toDoubleOrNull() ?: return raw
        return if (d == d.toLong().toDouble()) "%,d".format(d.toLong()) else "%,.0f".format(d)
    }
}
