package app.closer.ui.dates

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.closer.data.repository.DateIdeaSeed
import app.closer.domain.model.DateIdea
import app.closer.domain.model.DateMatch
import app.closer.domain.model.DateMatchSuggestion
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.combine
import kotlinx.coroutines.launch

data class DateMatchesUiState(
    val isLoading: Boolean = true,
    val error: String? = null,
    val coupleId: String? = null,
    val partnerName: String? = null,
    val mutualMatches: List<DateMatch> = emptyList(),
    val maybeMatches: List<DateMatchSuggestion> = emptyList()
)

data class DateMatchSuggestion(
    val dateIdeaId: String,
    val dateIdea: DateIdea,
    val partnerAction: SwipeAction
)

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

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

    init {
        loadMatches()
    }

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

                _uiState.value = DateMatchesUiState(
                    isLoading = false,
                    coupleId = couple?.id,
                    partnerName = partnerName
                )

                if (couple != null && uid != null && partnerId != null) {
                    observeMatches(couple.id, uid, partnerId)
                }
            } catch (e: Exception) {
                _uiState.value = DateMatchesUiState(
                    isLoading = false,
                    error = e.message ?: "Could not load matches."
                )
            }
        }
    }

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

        viewModelScope.launch {
            combine(matchesFlow, partnerSwipesFlow, ownSwipesFlow) { matches, partnerSwipes, ownSwipes ->
                val ownLoveIds = ownSwipes
                    .filter { it.action == SwipeAction.LOVE }
                    .map { it.dateIdeaId }
                    .toSet()
                val ownMaybeIds = ownSwipes
                    .filter { it.action == SwipeAction.MAYBE }
                    .map { it.dateIdeaId }
                    .toSet()
                val matchedIdeaIds = matches.map { it.dateIdeaId }.toSet()

                val maybeSuggestions = partnerSwipes
                    .filter { it.action != SwipeAction.SKIP }
                    .mapNotNull { partnerSwipe ->
                        val ideaId = partnerSwipe.dateIdeaId
                        if (ideaId in matchedIdeaIds) return@mapNotNull null
                        val ownLoved = ideaId in ownLoveIds
                        val ownMaybe = ideaId in ownMaybeIds
                        when {
                            ownLoved && partnerSwipe.action == SwipeAction.MAYBE -> ideaId to SwipeAction.MAYBE
                            ownMaybe && partnerSwipe.action == SwipeAction.LOVE -> ideaId to SwipeAction.LOVE
                            else -> null
                        }
                    }
                    .mapNotNull { (ideaId, partnerAction) ->
                        DateIdeaSeed.byId(ideaId)?.let {
                            DateMatchSuggestion(ideaId, it, partnerAction)
                        }
                    }

                val enrichedMatches = matches.map { match ->
                    match.copy(dateIdea = DateIdeaSeed.byId(match.dateIdeaId))
                }

                DateMatchesUiState(
                    isLoading = false,
                    coupleId = coupleId,
                    partnerName = _uiState.value.partnerName,
                    mutualMatches = enrichedMatches,
                    maybeMatches = maybeSuggestions
                )
            }.collect { _uiState.value = it }
        }
    }

    fun retry() = loadMatches()

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