package app.closer.ui.dates

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.closer.domain.model.DateIdea
import app.closer.domain.model.DateMatch
import app.closer.domain.model.DateSwipe
import app.closer.domain.model.SwipeAction
import app.closer.domain.repository.AuthRepository
import app.closer.domain.repository.CoupleRepository
import app.closer.domain.repository.DateMatchRepository
import app.closer.domain.repository.UserRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

data class DateMatchUiState(
    val isLoading: Boolean = true,
    val error: String? = null,
    val coupleId: String? = null,
    val currentUserId: String? = null,
    val partnerName: String? = null,
    val dateIdeas: List<DateIdea> = emptyList(),
    val ownSwipes: Map<String, SwipeAction> = emptyMap(),
    val matches: List<DateMatch> = emptyList(),
    val currentIndex: Int = 0,
    val justMatched: DateMatch? = null
) {
    val currentIdea: DateIdea? get() = dateIdeas.getOrNull(currentIndex)
    val nextIdea: DateIdea? get() = dateIdeas.getOrNull(currentIndex + 1)
    val hasMore: Boolean get() = currentIndex < dateIdeas.size

    fun userAction(ideaId: String): SwipeAction? = ownSwipes[ideaId]
}

@HiltViewModel
class DateMatchViewModel @Inject constructor(
    private val repository: DateMatchRepository,
    private val authRepository: AuthRepository,
    private val coupleRepository: CoupleRepository,
    private val userRepository: UserRepository
) : ViewModel() {

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

    init {
        loadDateMatch()
    }

    private fun loadDateMatch() {
        viewModelScope.launch {
            _uiState.value = DateMatchUiState(isLoading = true)
            try {
                val uid = authRepository.currentUserId
                val couple = uid?.let { runCatching { coupleRepository.getCoupleForUser(it) }.getOrNull() }
                val partnerName = couple?.userIds?.firstOrNull { it != uid }?.let { partnerId ->
                    runCatching { userRepository.getUser(partnerId)?.displayName }
                        .onFailure { Log.w(TAG, "Could not load partner display name", it) }
                        .getOrNull()
                }
                val ideas = repository.getDateIdeas()
                _uiState.value = DateMatchUiState(
                    isLoading = false,
                    coupleId = couple?.id,
                    currentUserId = uid,
                    partnerName = partnerName,
                    dateIdeas = ideas
                )

                if (couple != null && uid != null) {
                    observeData(couple.id, uid)
                }
            } catch (e: Exception) {
                _uiState.value = DateMatchUiState(
                    isLoading = false,
                    error = e.message ?: "Could not load date ideas."
                )
            }
        }
    }

    private fun observeData(coupleId: String, userId: String) {
        val swipesFlow: Flow<List<DateSwipe>> = repository.observeOwnSwipes(coupleId, userId)
        val matchesFlow: Flow<List<DateMatch>> = repository.observeMatches(coupleId)

        viewModelScope.launch {
            // Matches are created server-side and stream in via observeMatches.
            // Track ids already seen so the "It's a match!" celebration only fires
            // for matches created after this screen started observing — not for
            // matches that already existed on load.
            var knownMatchIds: Set<String>? = null
            combine(swipesFlow, matchesFlow) { swipes, matches -> swipes to matches }
                .collect { (swipes, matches) ->
                    val newMatch = knownMatchIds?.let { known ->
                        matches.firstOrNull { it.id !in known }
                    }
                    knownMatchIds = matches.mapTo(mutableSetOf()) { it.id }
                    _uiState.update { state ->
                        state.copy(
                            ownSwipes = swipes.associate { it.dateIdeaId to it.action },
                            matches = matches,
                            justMatched = newMatch ?: state.justMatched
                        )
                    }
                }
        }
    }

    fun swipeCurrent(action: SwipeAction) {
        val current = _uiState.value.currentIdea ?: return
        val coupleId = _uiState.value.coupleId ?: return
        val userId = _uiState.value.currentUserId ?: return

        viewModelScope.launch {
            _uiState.update { it.copy(justMatched = null) }
            val result = repository.recordSwipe(coupleId, userId, current.id, action)
            result.fold(
                onSuccess = {
                    // Advance to the next idea. A resulting match (if both partners
                    // loved this idea) is created server-side and surfaces via the
                    // observeMatches flow, which sets justMatched.
                    _uiState.update { it.copy(currentIndex = it.currentIndex + 1) }
                },
                onFailure = { err ->
                    _uiState.update {
                        it.copy(error = err.message ?: "Could not save swipe.")
                    }
                }
            )
        }
    }

    fun skipCurrent() = swipeCurrent(SwipeAction.SKIP)
    fun maybeCurrent() = swipeCurrent(SwipeAction.MAYBE)
    fun loveCurrent() = swipeCurrent(SwipeAction.LOVE)

    fun dismissJustMatched() {
        _uiState.update { it.copy(justMatched = null) }
    }

    fun retry() = loadDateMatch()

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