/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.ui.contact

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.runicgateway.app.core.result.ApiResult
import com.runicgateway.app.data.repository.ContactRepository
import com.runicgateway.app.ui.ErrorKind
import com.runicgateway.app.ui.toUiState
import com.runicgateway.app.ui.UiState as LoadUiState
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

/** Contact form submission with client-side validation (PLAN.md §6.1). */
@HiltViewModel
class ContactViewModel @Inject constructor(
    private val contactRepository: ContactRepository,
) : ViewModel() {

    sealed interface Result {
        data object Sent : Result

        /** Site has no mailer; email directly at [email] instead. */
        data class Fallback(val email: String?) : Result
        data object ValidationError : Result
        data class Failed(val kind: ErrorKind) : Result
    }

    data class UiState(
        val name: String = "",
        val email: String = "",
        val message: String = "",
        val submitting: Boolean = false,
        val result: Result? = null,
    )

    private val _state = MutableStateFlow(UiState())
    val state: StateFlow<UiState> = _state.asStateFlow()

    fun onNameChange(value: String) = _state.update { it.copy(name = value, result = null) }
    fun onEmailChange(value: String) = _state.update { it.copy(email = value, result = null) }
    fun onMessageChange(value: String) = _state.update { it.copy(message = value, result = null) }

    fun send() {
        val s = _state.value
        if (s.submitting) return
        if (s.name.isBlank() || s.email.isBlank() || s.message.isBlank()) {
            _state.update { it.copy(result = Result.ValidationError) }
            return
        }
        _state.update { it.copy(submitting = true, result = null) }
        viewModelScope.launch {
            val result = when (val r = contactRepository.send(s.name.trim(), s.email.trim(), s.message.trim())) {
                is ApiResult.Ok ->
                    if (r.data.sent) Result.Sent else Result.Fallback(r.data.email)
                else -> {
                    val kind = (r.toUiState() as? LoadUiState.Error)?.kind ?: ErrorKind.SERVER
                    Result.Failed(kind)
                }
            }
            _state.update {
                // Clear the fields on a successful send; keep them on failure so the
                // user can retry without retyping.
                if (result is Result.Sent) {
                    UiState(result = result)
                } else {
                    it.copy(submitting = false, result = result)
                }
            }
        }
    }
}
