package de.tsschulz.timeclock.ui.auth

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import de.tsschulz.timeclock.data.auth.AuthRepository
import de.tsschulz.timeclock.data.auth.TokenStore
import de.tsschulz.timeclock.data.auth.UserProfile
import de.tsschulz.timeclock.data.api.TimeClockApiClient
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

data class AuthUiState(
    val bootstrapping: Boolean = true,
    val isAuthenticated: Boolean = false,
    val user: UserProfile? = null,
    val loginInProgress: Boolean = false,
    val error: String? = null,
    val googleLoginUrl: String? = null,
    val oauthPendingToken: String? = null,
    val oauthPendingEmail: String? = null,
    /** Gespeicherter Token, aber `/auth/me` ist fehlgeschlagen (z. B. offline). */
    val bootstrapWarn: String? = null,
)

class AuthViewModel(
    private val repository: AuthRepository,
) : ViewModel() {

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

    init {
        viewModelScope.launch { runBootstrap() }
    }

    fun googleLoginUrl(): String = repository.googleLoginUrl()

    private suspend fun runBootstrap() {
        val user = repository.restoreSession()
        val warn = if (user == null && repository.hasStoredToken()) {
            "Profil konnte nicht geladen werden. Bitte Netzwerk prüfen oder erneut versuchen."
        } else {
            null
        }
        _uiState.value = AuthUiState(
            bootstrapping = false,
            isAuthenticated = user != null,
            user = user,
            bootstrapWarn = warn,
        )
    }

    fun login(email: String, password: String, action: String) {
        if (email.isBlank() || password.isBlank()) {
            _uiState.update { it.copy(error = "E-Mail und Passwort sind erforderlich") }
            return
        }
        viewModelScope.launch {
            _uiState.update { it.copy(loginInProgress = true, error = null) }
            repository.login(email, password, action).fold(
                onSuccess = { user ->
                    _uiState.update {
                        it.copy(
                            loginInProgress = false,
                            isAuthenticated = true,
                            user = user,
                            error = null,
                            bootstrapWarn = null,
                        )
                    }
                },
                onFailure = { e ->
                    _uiState.update {
                        it.copy(
                            loginInProgress = false,
                            error = e.message ?: "Login fehlgeschlagen",
                        )
                    }
                },
            )
        }
    }

    fun logout() {
        viewModelScope.launch {
            repository.logout()
            _uiState.value = AuthUiState(bootstrapping = false)
        }
    }

    fun completeOAuthToken(token: String) {
        viewModelScope.launch {
            _uiState.update { it.copy(loginInProgress = true, error = null) }
            repository.completeOAuthLogin(token).fold(
                onSuccess = { user ->
                    _uiState.update {
                        it.copy(
                            loginInProgress = false,
                            isAuthenticated = true,
                            user = user,
                            error = null,
                            oauthPendingToken = null,
                            oauthPendingEmail = null,
                            bootstrapWarn = null,
                        )
                    }
                },
                onFailure = { e ->
                    _uiState.update { it.copy(loginInProgress = false, error = e.message ?: "Google-Login fehlgeschlagen") }
                },
            )
        }
    }

    fun requireOAuthLink(pendingToken: String, email: String?) {
        _uiState.update {
            it.copy(
                bootstrapping = false,
                loginInProgress = false,
                oauthPendingToken = pendingToken,
                oauthPendingEmail = email,
                error = null,
            )
        }
    }

    fun linkExistingOAuthAccount(email: String, password: String) {
        val pendingToken = _uiState.value.oauthPendingToken
        if (pendingToken.isNullOrBlank()) {
            _uiState.update { it.copy(error = "Keine Google-Verknüpfung offen") }
            return
        }
        viewModelScope.launch {
            _uiState.update { it.copy(loginInProgress = true, error = null) }
            repository.linkExistingOAuthAccount(pendingToken, email, password).fold(
                onSuccess = { user ->
                    _uiState.update {
                        it.copy(
                            loginInProgress = false,
                            isAuthenticated = true,
                            user = user,
                            oauthPendingToken = null,
                            oauthPendingEmail = null,
                        )
                    }
                },
                onFailure = { e ->
                    _uiState.update { it.copy(loginInProgress = false, error = e.message ?: "Google-Verknüpfung fehlgeschlagen") }
                },
            )
        }
    }

    fun retryBootstrap() {
        viewModelScope.launch {
            _uiState.update { it.copy(bootstrapping = true, bootstrapWarn = null) }
            runBootstrap()
        }
    }

    class Factory(
        private val application: Application,
    ) : ViewModelProvider.Factory {
        @Suppress("UNCHECKED_CAST")
        override fun <T : ViewModel> create(modelClass: Class<T>): T {
            val tokenStore = TokenStore(application)
            val api = TimeClockApiClient(tokenStore)
            val repo = AuthRepository(api, tokenStore)
            return AuthViewModel(repo) as T
        }
    }
}
