package com.fabledsword.minstrel.settings.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fabledsword.minstrel.api.ErrorCopy
import com.fabledsword.minstrel.models.ListenBrainzStatus
import com.fabledsword.minstrel.settings.data.MeRepository
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 javax.inject.Inject

data class ListenBrainzUiState(
    val isLoading: Boolean = true,
    val isSaving: Boolean = false,
    val status: ListenBrainzStatus? = null,
    val tokenInput: String = "",
    val message: String? = null,
)

/**
 * Backs the ListenBrainz card in Settings. Loads the caller's state
 * on init, then handles token-save and enabled-toggle. The token is
 * never read back from the server — the UI shows "token saved" /
 * "no token" based on [ListenBrainzStatus.tokenSet] without exposing
 * the value. Submit clears [tokenInput] on success so the field
 * acts as a write-only entry.
 */
@HiltViewModel
class ListenBrainzViewModel @Inject constructor(
    private val repository: MeRepository,
) : ViewModel() {

    private val internal = MutableStateFlow(ListenBrainzUiState())
    val state: StateFlow<ListenBrainzUiState> = internal.asStateFlow()

    init {
        refresh()
    }

    fun setTokenInput(value: String) {
        internal.update { it.copy(tokenInput = value) }
    }

    fun refresh() {
        viewModelScope.launch {
            internal.update { it.copy(isLoading = true, message = null) }
            try {
                val s = repository.getListenBrainz()
                internal.update { it.copy(isLoading = false, status = s) }
            } catch (
                @Suppress("TooGenericExceptionCaught") e: Throwable,
            ) {
                internal.update {
                    it.copy(
                        isLoading = false,
                        message = ErrorCopy.fromThrowable(e),
                    )
                }
            }
        }
    }

    fun saveToken() {
        val token = internal.value.tokenInput.trim()
        if (token.isEmpty() || internal.value.isSaving) return
        viewModelScope.launch {
            internal.update { it.copy(isSaving = true, message = null) }
            try {
                val s = repository.setListenBrainzToken(token)
                internal.update {
                    it.copy(
                        isSaving = false,
                        status = s,
                        tokenInput = "",
                        message = "Token saved.",
                    )
                }
            } catch (
                @Suppress("TooGenericExceptionCaught") e: Throwable,
            ) {
                internal.update {
                    it.copy(
                        isSaving = false,
                        message = ErrorCopy.fromThrowable(e),
                    )
                }
            }
        }
    }

    fun setEnabled(enabled: Boolean) {
        if (internal.value.isSaving) return
        viewModelScope.launch {
            internal.update { it.copy(isSaving = true, message = null) }
            try {
                val s = repository.setListenBrainzEnabled(enabled)
                internal.update { it.copy(isSaving = false, status = s) }
            } catch (
                @Suppress("TooGenericExceptionCaught") e: Throwable,
            ) {
                internal.update {
                    it.copy(
                        isSaving = false,
                        message = ErrorCopy.fromThrowable(e),
                    )
                }
            }
        }
    }
}
