package app.closer.ui.wheel

import android.util.Log
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.closer.core.navigation.AppRoute
import app.closer.domain.model.GameType
import app.closer.domain.model.SessionLength
import app.closer.domain.repository.QuestionRepository
import app.closer.domain.usecase.GameSessionManager
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

data class SpinWheelUiState(
    val isLoading: Boolean = true,
    val categoryName: String = "",
    val isSpinning: Boolean = false,
    val spunAndReady: Boolean = false,
    val selectedLength: SessionLength = SessionLength.STANDARD,
    val error: String? = null,
    val navigateTo: String? = null
)

@HiltViewModel
class SpinWheelViewModel @Inject constructor(
    savedStateHandle: SavedStateHandle,
    private val repository: QuestionRepository,
    private val sessionStore: LocalWheelSessionStore,
    private val gameSessionManager: GameSessionManager
) : ViewModel() {

    private val categoryId: String = savedStateHandle["categoryId"] ?: ""

    private val _uiState = MutableStateFlow(SpinWheelUiState())
    val uiState: StateFlow<SpinWheelUiState> = _uiState.asStateFlow()

    init {
        loadCategory()
    }

    private fun loadCategory() {
        viewModelScope.launch {
            val category = runCatching { repository.getCategoryById(categoryId) }
                .onFailure { Log.w(TAG, "Could not load wheel category", it) }
                .getOrNull()
            _uiState.update {
                it.copy(
                    isLoading = false,
                    categoryName = category?.displayName ?: categoryId
                )
            }
        }
    }

    fun spin() {
        if (_uiState.value.isSpinning) return
        viewModelScope.launch {
            _uiState.update { it.copy(isSpinning = true, error = null) }
            val questions = runCatching {
                repository.getQuestionsByCategory(categoryId).shuffled().take(_uiState.value.selectedLength.count)
            }
                .onFailure { Log.w(TAG, "Could not load wheel questions", it) }
                .getOrElse { emptyList() }

            if (questions.isEmpty()) {
                _uiState.update {
                    it.copy(isSpinning = false, error = "No questions found for this category.")
                }
                return@launch
            }

            val category = runCatching { repository.getCategoryById(categoryId) }
                .onFailure { Log.w(TAG, "Could not load wheel category for session", it) }
                .getOrNull()
            sessionStore.activeSession = LocalWheelSession(
                categoryId = categoryId,
                categoryName = category?.displayName ?: categoryId,
                questions = questions
            )
            _uiState.update { it.copy(isSpinning = false, spunAndReady = true) }
        }
    }

    fun startSession() {
        viewModelScope.launch {
            val userId = gameSessionManager.currentUserId
            if (userId == null) {
                _uiState.update { it.copy(error = "Not logged in") }
                return@launch
            }

            val couple = runCatching {
                gameSessionManager.getCoupleForUser(userId)
            }.getOrNull()

            if (couple == null) {
                _uiState.update { it.copy(error = "Not in a couple") }
                return@launch
            }

            val hasActive = runCatching {
                gameSessionManager.hasActiveSession(couple.id)
            }.getOrNull() ?: false

            if (hasActive) {
                _uiState.update {
                    it.copy(navigateTo = AppRoute.WAITING_FOR_PARTNER)
                }
                return@launch
            }

            val questionIds = sessionStore.activeSession?.questions?.map { it.id }
            val startResult = runCatching {
                gameSessionManager.startGame(
                    userId = userId,
                    gameType = GameType.WHEEL,
                    categoryId = categoryId,
                    questionIds = questionIds
                )
            }.getOrElse { Result.failure(it) }

            when {
                startResult.isSuccess -> {
                    val sessionId = startResult.getOrThrow()
                    _uiState.update { it.copy(navigateTo = AppRoute.wheelSession(sessionId)) }
                }
                startResult.exceptionOrNull()?.message?.startsWith("partner_active_session|") == true -> {
                    _uiState.update { it.copy(navigateTo = AppRoute.WAITING_FOR_PARTNER) }
                }
                else -> {
                    Log.w(TAG, "Could not start wheel session", startResult.exceptionOrNull())
                    _uiState.update { it.copy(error = "Could not start session") }
                }
            }
        }
    }

    fun setLength(len: SessionLength) {
        // Resets spunAndReady so the user re-spins with the new count.
        _uiState.update { it.copy(selectedLength = len, spunAndReady = false) }
    }

    fun onNavigated() {
        _uiState.update { it.copy(navigateTo = null) }
    }

    companion object {
        private const val TAG = "SpinWheelViewModel"
    }
}
