package com.fabledsword.minstrel.auth.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fabledsword.minstrel.api.ErrorCopy
import com.fabledsword.minstrel.auth.AuthController
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 LoginFormState(
    val username: String = "",
    val password: String = "",
    val isSubmitting: Boolean = false,
    val errorMessage: String? = null,
    val signedIn: Boolean = false,
)

@HiltViewModel
class LoginViewModel @Inject constructor(
    private val auth: AuthController,
) : ViewModel() {

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

    fun setUsername(value: String) {
        internal.update { it.copy(username = value, errorMessage = null) }
    }

    fun setPassword(value: String) {
        internal.update { it.copy(password = value, errorMessage = null) }
    }

    fun submit() {
        val s = internal.value
        if (s.username.isBlank() || s.password.isBlank() || s.isSubmitting) return
        viewModelScope.launch {
            internal.update { it.copy(isSubmitting = true, errorMessage = null) }
            try {
                auth.signIn(s.username, s.password)
                internal.update { it.copy(isSubmitting = false, signedIn = true) }
            } catch (
                @Suppress("TooGenericExceptionCaught") e: Throwable,
            ) {
                internal.update {
                    it.copy(
                        isSubmitting = false,
                        errorMessage = ErrorCopy.fromThrowable(e),
                    )
                }
            }
        }
    }

    /** Called after the navigation away from /login completes. */
    fun consumeSignedIn() {
        internal.update { it.copy(signedIn = false) }
    }
}
