package app.closer.ui.outcomes

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import app.closer.domain.model.Outcome
import app.closer.domain.model.OutcomeDay
import app.closer.domain.model.OutcomeDayKey
import app.closer.domain.model.OutcomeScores
import app.closer.domain.repository.AuthRepository
import app.closer.domain.repository.CoupleRepository
import app.closer.domain.repository.OutcomeRepository
import app.closer.domain.repository.SettingsRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.time.Instant
import java.time.LocalDate
import java.time.ZoneId
import javax.inject.Inject

/**
 * Manual test flow:
 *  1. Open Your Progress; verify empty baseline state.
 *  2. Submit baseline via OutcomeCheckInDialog; viewModel marks baseline shown and reloads.
 *  3. Submit day_30 outcome; verify delta card computes.
 *  4. Verify submitOutcome result reported to UI via snackbar/error.
 */
data class YourProgressUiState(
    val isLoading: Boolean = false,
    val error: String? = null,
    val outcomes: List<Outcome> = emptyList(),
    val showBaselineDialog: Boolean = false,
    val showFollowUpDialog: Boolean = false,
    val pendingDayKey: OutcomeDayKey? = null,
    val submitSuccess: Boolean = false
) {
    val baseline: Outcome? = outcomes.firstOrNull { it.dayKey == OutcomeDay.BASELINE.key }
    val latest: Outcome? = outcomes
        .filter { it.dayKey != OutcomeDay.BASELINE.key && it.scores != null }
        .maxByOrNull { OutcomeDay.fromKey(it.dayKey)?.ordinal ?: -1 }
}

@HiltViewModel
class YourProgressViewModel @Inject constructor(
    private val authRepository: AuthRepository,
    private val coupleRepository: CoupleRepository,
    private val outcomeRepository: OutcomeRepository,
    private val settingsRepository: SettingsRepository
) : ViewModel() {

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

    fun load() {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true, error = null, submitSuccess = false) }
            try {
                val userId = authRepository.currentUserId
                    ?: throw IllegalStateException("Not signed in.")
                val couple = coupleRepository.getCoupleForUser(userId)
                    ?: throw IllegalStateException("Not paired.")
                val outcomes = outcomeRepository.getOutcomes(couple.id)

                val baselineRecorded = outcomes.any { it.dayKey == OutcomeDay.BASELINE.key }
                val promptDay = dueFollowUpDay(couple.createdAt, outcomes)

                _uiState.update {
                    it.copy(
                        isLoading = false,
                        outcomes = outcomes,
                        showBaselineDialog = !baselineRecorded,
                        showFollowUpDialog = promptDay != null,
                        pendingDayKey = promptDay?.key
                    )
                }
            } catch (e: Exception) {
                _uiState.update { it.copy(isLoading = false, error = e.message ?: "Couldn’t load progress.") }
            }
        }
    }

    fun submitOutcome(dayKey: OutcomeDayKey, scores: OutcomeScores) {
        viewModelScope.launch {
            _uiState.update { it.copy(isLoading = true, error = null, submitSuccess = false) }
            try {
                val userId = authRepository.currentUserId
                    ?: throw IllegalStateException("Not signed in.")
                val couple = coupleRepository.getCoupleForUser(userId)
                    ?: throw IllegalStateException("Not paired.")
                outcomeRepository.submitOutcome(couple.id, dayKey, scores).getOrThrow()

                if (dayKey == OutcomeDay.BASELINE.key) {
                    settingsRepository.markOutcomeBaselineShown()
                }
                settingsRepository.setOutcomeLastPromptedDay(dayKey)

                _uiState.update { it.copy(submitSuccess = true) }
                load()
            } catch (e: Exception) {
                _uiState.update { it.copy(isLoading = false, error = e.message ?: "Couldn’t submit check-in.") }
            }
        }
    }

    fun dismissBaselineDialog() {
        viewModelScope.launch {
            settingsRepository.markOutcomeBaselineShown()
            _uiState.update { it.copy(showBaselineDialog = false) }
        }
    }

    fun dismissFollowUpDialog() {
        _uiState.update { it.copy(showFollowUpDialog = false) }
    }

    fun consumeSuccess() {
        _uiState.update { it.copy(submitSuccess = false) }
    }

    fun consumeError() {
        _uiState.update { it.copy(error = null) }
    }

    private fun dueFollowUpDay(createdAt: Long, outcomes: List<Outcome>): OutcomeDay? {
        val paired = LocalDate.ofInstant(Instant.ofEpochMilli(createdAt), ZoneId.systemDefault())
        val today = LocalDate.now()
        val ageDays = java.time.temporal.ChronoUnit.DAYS.between(paired, today)

        val due = listOf(
            OutcomeDay.DAY_30 to 30,
            OutcomeDay.DAY_60 to 60,
            OutcomeDay.DAY_90 to 90
        ).firstOrNull { (_, days) -> ageDays >= days }
            ?: return null

        return if (outcomes.any { it.dayKey == due.first.key }) null else due.first
    }
}
