package com.fabledsword.minstrel.admin.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fabledsword.minstrel.admin.data.AdminUsersRepository
import com.fabledsword.minstrel.api.ErrorCopy
import com.fabledsword.minstrel.connectivity.NetworkStatusController
import com.fabledsword.minstrel.connectivity.recoveries
import com.fabledsword.minstrel.models.AdminUserRef
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject

sealed interface AdminUsersUiState {
    data object Loading : AdminUsersUiState
    data object Empty : AdminUsersUiState
    data class Success(val users: List<AdminUserRef>) : AdminUsersUiState
    data class Error(val message: String) : AdminUsersUiState
}

@HiltViewModel
class AdminUsersViewModel @Inject constructor(
    private val repository: AdminUsersRepository,
    networkStatus: NetworkStatusController,
) : ViewModel() {

    private val internal = MutableStateFlow<AdminUsersUiState>(AdminUsersUiState.Loading)
    val uiState: StateFlow<AdminUsersUiState> = internal.asStateFlow()

    init {
        refresh()
        // Screen-level auto-recovery (issue #1245): reload a failed list
        // when server health returns instead of waiting for a manual pull.
        viewModelScope.launch {
            networkStatus.recoveries().collect {
                if (internal.value is AdminUsersUiState.Error) refresh()
            }
        }
    }

    fun refresh(): Job = viewModelScope.launch {
        internal.value = AdminUsersUiState.Loading
        try {
            val users = repository.list()
            internal.value = if (users.isEmpty()) {
                AdminUsersUiState.Empty
            } else {
                AdminUsersUiState.Success(users)
            }
        } catch (
            @Suppress("TooGenericExceptionCaught") e: Throwable,
        ) {
            internal.value = AdminUsersUiState.Error(ErrorCopy.fromThrowable(e))
        }
    }

    fun setAdmin(id: String, isAdmin: Boolean) = patch(id, { it.copy(isAdmin = isAdmin) }) {
        repository.setAdmin(it, isAdmin)
    }

    fun setAutoApprove(id: String, autoApprove: Boolean) =
        patch(id, { it.copy(autoApproveRequests = autoApprove) }) {
            repository.setAutoApprove(it, autoApprove)
        }

    fun resetPassword(id: String, newPassword: String) {
        viewModelScope.launch {
            runCatching { repository.resetPassword(id, newPassword) }
        }
    }

    fun delete(id: String) {
        val before = internal.value
        if (before is AdminUsersUiState.Success) {
            val filtered = before.users.filterNot { it.id == id }
            internal.value = if (filtered.isEmpty()) {
                AdminUsersUiState.Empty
            } else {
                AdminUsersUiState.Success(filtered)
            }
        }
        viewModelScope.launch {
            try {
                repository.delete(id)
            } catch (
                @Suppress("TooGenericExceptionCaught", "SwallowedException") e: Throwable,
            ) {
                refresh()
            }
        }
    }

    private fun patch(
        id: String,
        mutate: (AdminUserRef) -> AdminUserRef,
        action: suspend (String) -> Unit,
    ) {
        val before = internal.value
        if (before is AdminUsersUiState.Success) {
            internal.value = AdminUsersUiState.Success(
                before.users.map { if (it.id == id) mutate(it) else it },
            )
        }
        viewModelScope.launch {
            try {
                action(id)
            } catch (
                @Suppress("TooGenericExceptionCaught", "SwallowedException") e: Throwable,
            ) {
                // Server-side guard might have rejected the toggle (e.g.
                // last-admin protection); refetch reconciles state.
                refresh()
            }
        }
    }
}
