package com.hermes.app.feature.feed

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.hermes.app.R
import com.hermes.app.core.analytics.HermesAnalyticsTracker
import com.hermes.app.core.errors.mapUserFacingError
import com.hermes.app.core.localization.HermesLocalizationStore
import com.hermes.app.data.HermesRepository
import com.hermes.app.domain.HermesRound
import java.util.Locale
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.stateIn
import kotlinx.datetime.Instant

data class FeedUiState(
    val title: String,
    val subtitle: String,
    val heroTitle: String,
    val heroSubtitle: String,
    val lockLabel: String,
    val lockValue: String,
    val oddsLabel: String,
    val oddsValue: String,
    val ctaText: String,
    val retryText: String,
    val hasRound: Boolean,
    val isLoading: Boolean,
    val bannerMessage: String?,
)

class FeedViewModel(
    private val repository: HermesRepository,
    private val localizationStore: HermesLocalizationStore,
    private val analyticsTracker: HermesAnalyticsTracker,
) : ViewModel() {
    private val roundFlow = repository.currentRound
    private val localeFlow = localizationStore.localeCode
    private val nowFlow = flow {
        while (true) {
            emit(repository.serverNow())
            delay(1_000)
        }
    }

    val uiState: StateFlow<FeedUiState> = combine(roundFlow, localeFlow, repository.isLoading, repository.errorCause, nowFlow) { round, localeCode, isLoading, errorCause, now ->
        buildUiState(round = round, localeCode = localeCode, isLoading = isLoading, errorCause = errorCause, now = now)
    }.stateIn(
        scope = viewModelScope,
        started = SharingStarted.Eagerly,
        initialValue = buildUiState(
            round = roundFlow.value,
            localeCode = localeFlow.value,
            isLoading = repository.isLoading.value,
            errorCause = repository.errorCause.value,
            now = repository.serverNow(),
        ),
    )

    init {
        analyticsTracker.track("feed_viewed", attributes = mapOf("screen_name" to "feed"))
        analyticsTracker.track("screen_viewed", attributes = mapOf("screen_name" to "feed"))
    }

    fun onWatchPreview() {
        if (roundFlow.value == null) {
            return
        }

        analyticsTracker.track("next_round_requested", attributes = mapOf("screen_name" to "feed"))
        analyticsTracker.track(
            "cta_pressed",
            attributes = mapOf("screen_name" to "feed", "action" to "watch_preview"),
        )
    }

    private fun buildUiState(round: HermesRound?, localeCode: String, isLoading: Boolean, errorCause: Throwable?, now: Instant): FeedUiState {
        val bannerMessage = mapUserFacingError(localizationStore, localeCode, errorCause)
        val hasRound = round != null
        val showLoading = isLoading && !hasRound

        return FeedUiState(
            title = localized(localeCode, R.string.feed_title),
            subtitle = localized(localeCode, R.string.feed_subtitle),
            heroTitle = round?.let { localizedEventTitle(it, localeCode) } ?: localized(localeCode, R.string.common_loading),
            heroSubtitle = when {
                showLoading -> localized(localeCode, R.string.common_loading)
                bannerMessage != null && !hasRound -> bannerMessage
                hasRound -> localized(localeCode, R.string.feed_hero_subtitle)
                else -> localized(localeCode, R.string.feed_subtitle)
            },
            lockLabel = localized(localeCode, R.string.feed_lock_label),
            lockValue = round?.let { formatCountdown(it.event.lockAt, now) } ?: "--:--",
            oddsLabel = localized(localeCode, R.string.feed_odds_label),
            oddsValue = round?.let { formatOdds(it) } ?: "--",
            ctaText = localized(localeCode, R.string.feed_cta),
            retryText = localized(localeCode, R.string.common_retry),
            hasRound = hasRound,
            isLoading = showLoading,
            bannerMessage = bannerMessage,
        )
    }

    private fun localized(localeCode: String, resId: Int): String {
        return localizationStore.string(localeCode, resId)
    }

    private fun localizedEventTitle(round: HermesRound, localeCode: String): String {
        return if (localeCode == "sv") round.event.titleSv else round.event.titleEn
    }

    private fun formatCountdown(lockAt: Instant, now: Instant): String {
        val remainingMillis = (lockAt.toEpochMilliseconds() - now.toEpochMilliseconds()).coerceAtLeast(0)
        val totalSeconds = (remainingMillis / 1_000).toInt()
        val minutes = totalSeconds / 60
        val seconds = totalSeconds % 60
        return String.format(Locale.US, "%02d:%02d", minutes, seconds)
    }

    private fun formatOdds(round: HermesRound): String {
        val oddsByOutcomeId = round.oddsVersion.odds.associateBy { it.outcomeId }
        return round.market.outcomes
            .sortedBy { it.sortOrder }
            .mapNotNull { outcome ->
                oddsByOutcomeId[outcome.id]?.decimalOdds?.let { String.format(Locale.US, "%.2f", it) }
            }
            .joinToString(" / ")
    }
}
