package org.zaine.management.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.zaine.management.data.BackendRepository
import org.zaine.management.data.NetworkResult
import org.zaine.management.data.api.TodayStatusDto
import org.zaine.management.data.api.WirdEntryDto
import org.zaine.management.data.api.WirdEntryRequest
import java.time.LocalDate
import javax.inject.Inject

data class WirdUiState(
    val date: String = LocalDate.now().toString(),
    val wirdType: String = "durood",
    val value: String = "",
    val notes: String = "",
    val entries: List<WirdEntryDto> = emptyList(),
    val loading: Boolean = false,
    val error: String? = null,
    val saved: Boolean = false
)

@HiltViewModel
class WirdViewModel @Inject constructor(
    private val repository: BackendRepository
) : ViewModel() {
    private val _state = MutableStateFlow(WirdUiState(loading = true))
    val state: StateFlow<WirdUiState> = _state.asStateFlow()

    init {
        refresh()
    }

    fun setDate(value: String) = update { copy(date = value, saved = false) }
    fun setWirdType(value: String) = update { copy(wirdType = value, saved = false) }
    fun setValue(value: String) = update { copy(value = value, saved = false) }
    fun setNotes(value: String) = update { copy(notes = value, saved = false) }

    fun refresh() {
        viewModelScope.launch {
            update { copy(loading = true, error = null) }
            when (val result = repository.todayWirdEntries()) {
                is NetworkResult.Success -> update { copy(loading = false, entries = result.data) }
                is NetworkResult.Error -> update { copy(loading = false, error = result.message) }
                NetworkResult.Loading -> Unit
            }
        }
    }

    fun submit() {
        val current = _state.value
        val numericValue = current.value.toDoubleOrNull()
        if (numericValue == null) {
            update { copy(error = "Enter a numeric value") }
            return
        }
        viewModelScope.launch {
            update { copy(loading = true, error = null, saved = false) }
            val request = WirdEntryRequest(
                wirdType = current.wirdType,
                date = current.date,
                value = numericValue,
                notes = current.notes.ifBlank { null }
            )
            when (val result = repository.createWirdEntry(request)) {
                is NetworkResult.Success -> update {
                    copy(
                        loading = false,
                        value = "",
                        notes = "",
                        saved = true,
                        entries = listOf(result.data) + entries
                    )
                }
                is NetworkResult.Error -> update { copy(loading = false, error = result.message) }
                NetworkResult.Loading -> Unit
            }
        }
    }

    private fun update(block: WirdUiState.() -> WirdUiState) {
        _state.value = _state.value.block()
    }
}

data class HistoryUiState(
    val from: LocalDate = LocalDate.now().minusDays(30),
    val to: LocalDate = LocalDate.now(),
    val checkins: List<TodayStatusDto> = emptyList(),
    val wirdEntries: List<WirdEntryDto> = emptyList(),
    val loading: Boolean = false,
    val error: String? = null
)

@HiltViewModel
class HistoryViewModel @Inject constructor(
    private val repository: BackendRepository
) : ViewModel() {
    private val _state = MutableStateFlow(HistoryUiState(loading = true))
    val state: StateFlow<HistoryUiState> = _state.asStateFlow()

    init {
        refresh()
    }

    fun refresh() {
        val current = _state.value
        viewModelScope.launch {
            update { copy(loading = true, error = null) }
            val checkins = repository.checkinHistory(current.from.toString(), current.to.toString())
            val wird = repository.wirdEntries(current.from.toString(), current.to.toString())
            if (checkins is NetworkResult.Success && wird is NetworkResult.Success) {
                update { copy(loading = false, checkins = checkins.data, wirdEntries = wird.data) }
            } else {
                val message = (checkins as? NetworkResult.Error)?.message
                    ?: (wird as? NetworkResult.Error)?.message
                    ?: "Unable to load history"
                update { copy(loading = false, error = message) }
            }
        }
    }

    private fun update(block: HistoryUiState.() -> HistoryUiState) {
        _state.value = _state.value.block()
    }
}
