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

import com.runicgateway.app.R
import com.runicgateway.app.data.api.dto.RosterCharDto
import com.runicgateway.app.data.api.dto.RosterDto
import com.runicgateway.app.data.api.dto.SettingsDto
import com.runicgateway.app.data.api.dto.ShardLinkDto
import com.runicgateway.app.data.api.dto.ShardLinkResultDto
import com.runicgateway.app.data.api.fake.FakePlayerShardApi
import com.runicgateway.app.data.api.fake.FakePublicApi
import com.runicgateway.app.data.repository.PlayerShardRepository
import com.runicgateway.app.data.repository.SettingsRepository
import com.runicgateway.app.ui.UiState
import com.runicgateway.app.util.MainDispatcherRule
import com.runicgateway.app.util.httpError
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Rule
import org.junit.Test

class CharactersViewModelTest {

    @get:Rule val mainDispatcher = MainDispatcherRule()

    private val playerApi = FakePlayerShardApi()
    private val publicApi = FakePublicApi()
    private fun viewModel() = CharactersViewModel(
        PlayerShardRepository(playerApi),
        SettingsRepository(publicApi),
    )

    @Test fun loadsAccountsRostersAndSignupFlag() {
        playerApi.accounts = listOf(ShardLinkDto(account = "acct1"))
        playerApi.roster = RosterDto(acct = "acct1", chars = listOf(RosterCharDto(serial = "0x24C", name = "Gwen")))
        publicApi.settings = SettingsDto(gameAccountSignup = true)
        val vm = viewModel()

        assertEquals(listOf("acct1"), (vm.state.value.accounts as UiState.Success).data)
        val roster = vm.state.value.rosters["acct1"]
        assertTrue(roster is UiState.Success)
        assertEquals("Gwen", (roster as UiState.Success).data.first().name)
        assertTrue(vm.state.value.signupEnabled)
    }

    @Test fun accountsErrorSurfacesError() {
        playerApi.error = httpError(503)
        assertTrue(viewModel().state.value.accounts is UiState.Error)
    }

    @Test fun linkBlankCodeIsIgnored() {
        val vm = viewModel()
        vm.link("   ")
        assertEquals(null, vm.state.value.feedback)
    }

    @Test fun linkSuccessShowsOkAndReloads() {
        playerApi.linkResult = ShardLinkResultDto(linked = true, account = "acct1")
        val vm = viewModel()
        vm.link("CODE1")
        val fb = vm.state.value.feedback!!
        assertTrue(fb.ok)
        assertEquals(R.string.player_link_ok, fb.messageRes)
        assertFalse(vm.state.value.busy)
    }

    @Test fun linkBadCodeMapsTo400Copy() {
        playerApi.error = httpError(400)
        val vm = viewModel()
        vm.link("BAD")
        assertEquals(R.string.player_link_bad_code, vm.state.value.feedback!!.messageRes)
    }

    @Test fun createAccountRejectsShortPasswordWithoutApiCall() {
        val vm = viewModel()
        vm.createAccount(account = "acct1", password = "short") // < 8 chars
        assertEquals(null, vm.state.value.feedback) // guarded before any call/feedback
    }

    @Test fun createAccountTakenMapsTo409Copy() {
        playerApi.error = httpError(409)
        val vm = viewModel()
        vm.createAccount(account = "acct1", password = "longenough")
        assertEquals(R.string.player_create_taken, vm.state.value.feedback!!.messageRes)
    }
}
