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

import androidx.lifecycle.SavedStateHandle
import com.runicgateway.app.data.api.dto.CharProfileDto
import com.runicgateway.app.data.api.dto.PlayerHouseDto
import com.runicgateway.app.data.api.dto.ShardLinkDto
import com.runicgateway.app.data.api.dto.VendorDto
import com.runicgateway.app.data.api.dto.VendorSaleDto
import com.runicgateway.app.data.api.dto.VendorSnapshotDto
import com.runicgateway.app.data.api.fake.FakePlayerShardApi
import com.runicgateway.app.data.repository.PlayerShardRepository
import com.runicgateway.app.ui.ErrorKind
import com.runicgateway.app.ui.UiState
import com.runicgateway.app.ui.navigation.Routes
import com.runicgateway.app.util.MainDispatcherRule
import com.runicgateway.app.util.httpError
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test

/** ViewModels over the player self-service game-data API (own chars, vendors, houses). */
class PlayerViewModelTest {

    @get:Rule val mainDispatcher = MainDispatcherRule()

    private val api = FakePlayerShardApi()
    private val repository = PlayerShardRepository(api)

    // ── My houses ───────────────────────────────────────────────────────────
    @Test fun myHousesLoadsOwnHouses() {
        api.houses = listOf(PlayerHouseDto(serial = "0x40001", name = "Keep", isIdoc = false))
        val vm = MyHousesViewModel(repository)
        assertEquals("Keep", (vm.state.value as UiState.Success).data.first().name)
    }

    @Test fun myHousesShardOfflineIsShardOfflineError() {
        api.error = httpError(503)
        val state = MyHousesViewModel(repository).state.value
        assertEquals(ErrorKind.SHARD_OFFLINE, (state as UiState.Error).kind)
    }

    // ── Character sheet (SavedStateHandle serial) ─────────────────────────────
    @Test fun characterLoadsBySerial() {
        api.char = CharProfileDto(serial = "0x24C", name = "Gwen", online = true)
        val vm = CharacterViewModel(repository, SavedStateHandle(mapOf(Routes.Args.SERIAL to "0x24C")))
        assertEquals("Gwen", (vm.state.value as UiState.Success).data.name)
    }

    @Test fun characterForbiddenIsNotFound() {
        api.error = httpError(403)
        val vm = CharacterViewModel(repository, SavedStateHandle(mapOf(Routes.Args.SERIAL to "0x1")))
        // 403 isn't a mapped status -> SERVER bucket (only 404/429/503 are special-cased).
        assertTrue(vm.state.value is UiState.Error)
    }

    // ── Vendors (per-account snapshots + sales) ───────────────────────────────
    @Test fun vendorsLoadsAccountsThenPerAccountSnapshots() {
        api.accounts = listOf(ShardLinkDto(account = "acct1"))
        api.vendors = VendorSnapshotDto(acct = "acct1", vendors = listOf(VendorDto(serial = "0x9", shopName = "Wares")))
        api.sales = listOf(VendorSaleDto(itemType = "sword", price = 100))
        val vm = VendorsViewModel(repository)

        val accounts = vm.state.value.accounts
        assertTrue(accounts is UiState.Success)
        assertEquals(listOf("acct1"), (accounts as UiState.Success).data)
        // Each account's vendors loaded into the per-account map.
        val perAccount = vm.state.value.vendors["acct1"]
        assertTrue(perAccount is UiState.Success)
        assertEquals("Wares", (perAccount as UiState.Success).data.first().shopName)
        assertTrue(vm.state.value.sales is UiState.Success)
    }

    @Test fun vendorsAccountsErrorSurfacesError() {
        api.error = java.io.IOException("offline")
        val vm = VendorsViewModel(repository)
        assertTrue(vm.state.value.accounts is UiState.Error)
        assertTrue(vm.state.value.sales is UiState.Error)
    }
}
