/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.data.api.dto

import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test

/**
 * Decode tests for the public shard board DTOs (`/public/shard/…`), covering the
 * computed helpers ([ActorDto.label], [ShardStatusDto.isOnline]) and the
 * permissive board payloads (champ/guild/governor/house/presence).
 */
class ShardBoardDtoTest {

    private val json = Json {
        ignoreUnknownKeys = true
        explicitNulls = false
        coerceInputValues = true
    }

    @Test fun actorLabelPrefersNameThenAcctThenFallback() {
        assertEquals("Gwen", json.decodeFromString<ActorDto>("""{"name":"Gwen","acct":"g01"}""").label)
        assertEquals("g01", json.decodeFromString<ActorDto>("""{"acct":"g01"}""").label)
        assertEquals("Someone", json.decodeFromString<ActorDto>("{}").label)
    }

    @Test fun shardStatusIsOnlineOnlyWhenEnabledAndPluginConnected() {
        val online = json.decodeFromString<ShardStatusDto>(
            """{"enabled":true,"pluginConnected":true,"onlineCount":42,
                "economy":{"accounts":10,"gold":123456.0,"t":1000}}""",
        )
        assertTrue(online.isOnline)
        assertEquals(42, online.onlineCount)
        assertEquals(123456.0, online.economy!!.gold!!, 0.0)

        assertFalse(json.decodeFromString<ShardStatusDto>("""{"enabled":true,"pluginConnected":false}""").isOnline)
        assertFalse(json.decodeFromString<ShardStatusDto>("{}").isOnline)
    }

    @Test fun champDecodesBossAndProgressFields() {
        val dto = json.decodeFromString<ChampDto>(
            """{"serial":"0x1","category":"champion","name":"Rikktor","active":true,
                "bossUp":true,"boss":"Rikktor","level":3,"maxLevel":16,"kills":10,"maxKills":100,
                "hits":5000,"hitsMax":9000,"map":"Felucca","x":1,"y":2,"z":0}""",
        )
        assertTrue(dto.active)
        assertTrue(dto.bossUp)
        assertEquals(16, dto.maxLevel)
        assertEquals(5000L, dto.hits)
    }

    @Test fun guildDecodesLeaderActor() {
        val dto = json.decodeFromString<GuildDto>(
            """{"id":7,"name":"Knights","abbr":"KoT","members":12,"online":3,
                "leader":{"name":"Arthur","webId":"9931"}}""",
        )
        assertEquals("Knights", dto.name)
        assertEquals("Arthur", dto.leader!!.label)
        assertEquals("9931", dto.leader!!.webId)
    }

    @Test fun governorAndTermDecode() {
        val gov = json.decodeFromString<GovernorDto>(
            """{"city":"Britain","governor":{"name":"Dawn"},"electionPhase":"campaign"}""",
        )
        assertEquals("Britain", gov.city)
        assertEquals("Dawn", gov.governor!!.label)

        val term = json.decodeFromString<GovernorTermDto>(
            """{"city":"Britain","governor":{"name":"Dawn"},"startedAt":1000,"endedAt":2000,"votes":50}""",
        )
        assertEquals(50, term.votes)
        assertEquals(2000L, term.endedAt)
    }

    @Test fun houseAndPresenceAndStaffDecode() {
        val house = json.decodeFromString<HouseDto>(
            """{"serial":"0x40","name":"Tower","region":"Britain","isIdoc":true,"x":5,"y":6}""",
        )
        assertTrue(house.isIdoc)
        assertEquals("Tower", house.name)

        val presence = json.decodeFromString<PresenceDto>(
            """{"count":30,"byFacet":{"Felucca":10,"Trammel":20},"byRegion":{"Britain":5}}""",
        )
        assertEquals(30, presence.count)
        assertEquals(10, presence.byFacet["Felucca"])

        val staff = json.decodeFromString<OnlineStaffDto>("""{"serial":"0x2","name":"GM Bob","map":"Felucca","x":1,"y":2,"z":0}""")
        assertEquals("GM Bob", staff.name)
    }

    @Test fun feedEventDecodesPayloadObject() {
        val ev = json.decodeFromString<FeedEventDto>(
            """{"id":9,"kind":"champ.spawn","t":1234,"payload":{"name":"Rikktor"},"createdAt":"2026-07-22T00:00:00Z"}""",
        )
        assertEquals("champ.spawn", ev.kind)
        assertTrue(ev.payload!!.containsKey("name"))
    }
}
