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

import androidx.annotation.StringRes
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.runicgateway.app.R
import com.runicgateway.app.core.result.ApiResult
import com.runicgateway.app.data.repository.AdminRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject

/**
 * Drives the moderation actions (PLAN.md §1, M10): kick / ban / unban an account
 * and broadcast a system message, over the shard write plane (`/admin/shard/…`,
 * admin/moderator). These need a live sidecar — when the shard is offline the call
 * fails and the screen shows a clean error, never a crash (§7). The form fields live
 * in the screen; this VM owns only the busy + feedback state and the actions.
 */
@HiltViewModel
class AdminModerationViewModel @Inject constructor(
    private val admin: AdminRepository,
) : ViewModel() {

    data class Feedback(val ok: Boolean, @param:StringRes val messageRes: Int)

    data class State(val busy: Boolean = false, val feedback: Feedback? = null)

    private val _state = MutableStateFlow(State())
    val state: StateFlow<State> = _state.asStateFlow()

    fun clearFeedback() = _state.update { it.copy(feedback = null) }

    fun kick(account: String, serial: String) {
        if (account.isBlank() && serial.isBlank()) return badTarget()
        run(R.string.admin_mod_kicked) { admin.kick(account.ifBlank { null }, serial.ifBlank { null }) }
    }

    fun ban(account: String, serial: String, durationSec: Long?, reason: String) {
        if (account.isBlank() && serial.isBlank()) return badTarget()
        run(R.string.admin_mod_banned) {
            admin.ban(account.ifBlank { null }, serial.ifBlank { null }, durationSec, reason.ifBlank { null })
        }
    }

    fun unban(account: String) {
        if (account.isBlank()) return badTarget()
        run(R.string.admin_mod_unbanned) { admin.unban(account.trim()) }
    }

    fun broadcast(text: String, hue: Int?) {
        if (text.isBlank()) {
            _state.update { it.copy(feedback = Feedback(false, R.string.admin_mod_text_required)) }
            return
        }
        run(R.string.admin_mod_broadcasted) { admin.broadcast(text.trim(), hue) }
    }

    private fun badTarget() {
        _state.update { it.copy(feedback = Feedback(false, R.string.admin_mod_target_required)) }
    }

    private fun run(@StringRes okRes: Int, block: suspend () -> ApiResult<Unit>) {
        if (_state.value.busy) return
        _state.update { it.copy(busy = true, feedback = null) }
        viewModelScope.launch {
            val feedback = when (val r = block()) {
                is ApiResult.Ok -> Feedback(true, okRes)
                is ApiResult.HttpError -> Feedback(
                    false,
                    when (r.status) {
                        403 -> R.string.admin_forbidden
                        503 -> R.string.admin_mod_shard_offline
                        else -> R.string.admin_action_failed
                    },
                )
                is ApiResult.NetworkError -> Feedback(false, R.string.error_network)
            }
            _state.update { it.copy(busy = false, feedback = feedback) }
        }
    }
}
