package com.tt.honeyDue.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.tt.honeyDue.data.DataManager
import com.tt.honeyDue.data.IDataManager
import com.tt.honeyDue.models.AppleSignInRequest
import com.tt.honeyDue.models.AppleSignInResponse
import com.tt.honeyDue.models.GoogleSignInRequest
import com.tt.honeyDue.models.GoogleSignInResponse
import com.tt.honeyDue.models.AuthResponse
import com.tt.honeyDue.models.ForgotPasswordRequest
import com.tt.honeyDue.models.ForgotPasswordResponse
import com.tt.honeyDue.models.LoginRequest
import com.tt.honeyDue.models.RegisterRequest
import com.tt.honeyDue.models.ResetPasswordRequest
import com.tt.honeyDue.models.ResetPasswordResponse
import com.tt.honeyDue.models.Residence
import com.tt.honeyDue.models.User
import com.tt.honeyDue.models.VerifyEmailRequest
import com.tt.honeyDue.models.VerifyEmailResponse
import com.tt.honeyDue.models.VerifyResetCodeRequest
import com.tt.honeyDue.models.VerifyResetCodeResponse
import com.tt.honeyDue.network.ApiResult
import com.tt.honeyDue.network.APILayer
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch

class AuthViewModel(
    private val dataManager: IDataManager = DataManager,
) : ViewModel() {

    private val _loginState = MutableStateFlow<ApiResult<AuthResponse>>(ApiResult.Idle)
    val loginState: StateFlow<ApiResult<AuthResponse>> = _loginState

    private val _registerState = MutableStateFlow<ApiResult<AuthResponse>>(ApiResult.Idle)
    val registerState: StateFlow<ApiResult<AuthResponse>> = _registerState

    private val _verifyEmailState = MutableStateFlow<ApiResult<VerifyEmailResponse>>(ApiResult.Idle)
    val verifyEmailState: StateFlow<ApiResult<VerifyEmailResponse>> = _verifyEmailState

    private val _updateProfileState = MutableStateFlow<ApiResult<User>>(ApiResult.Idle)
    val updateProfileState: StateFlow<ApiResult<User>> = _updateProfileState

    /** Current authenticated user — derived from [IDataManager.currentUser]. APILayer writes through on login/register/getCurrentUser. */
    val currentUserState: StateFlow<ApiResult<User>> =
        dataManager.currentUser
            .map { if (it != null) ApiResult.Success(it) else ApiResult.Idle }
            .stateIn(
                viewModelScope,
                SharingStarted.Eagerly,
                dataManager.currentUser.value
                    ?.let { ApiResult.Success(it) } ?: ApiResult.Idle,
            )

    private val _forgotPasswordState = MutableStateFlow<ApiResult<ForgotPasswordResponse>>(ApiResult.Idle)
    val forgotPasswordState: StateFlow<ApiResult<ForgotPasswordResponse>> = _forgotPasswordState

    private val _verifyResetCodeState = MutableStateFlow<ApiResult<VerifyResetCodeResponse>>(ApiResult.Idle)
    val verifyResetCodeState: StateFlow<ApiResult<VerifyResetCodeResponse>> = _verifyResetCodeState

    private val _resetPasswordState = MutableStateFlow<ApiResult<ResetPasswordResponse>>(ApiResult.Idle)
    val resetPasswordState: StateFlow<ApiResult<ResetPasswordResponse>> = _resetPasswordState

    private val _appleSignInState = MutableStateFlow<ApiResult<AppleSignInResponse>>(ApiResult.Idle)
    val appleSignInState: StateFlow<ApiResult<AppleSignInResponse>> = _appleSignInState

    private val _googleSignInState = MutableStateFlow<ApiResult<GoogleSignInResponse>>(ApiResult.Idle)
    val googleSignInState: StateFlow<ApiResult<GoogleSignInResponse>> = _googleSignInState

    private val _deleteAccountState = MutableStateFlow<ApiResult<Unit>>(ApiResult.Idle)
    val deleteAccountState: StateFlow<ApiResult<Unit>> = _deleteAccountState

    fun login(username: String, password: String) {
        viewModelScope.launch {
            _loginState.value = ApiResult.Loading
            val result = APILayer.login(LoginRequest(username, password))
            // APILayer.login already stores token in DataManager
            _loginState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun register(username: String, email: String, password: String) {
        viewModelScope.launch {
            _registerState.value = ApiResult.Loading
            val result = APILayer.register(
                RegisterRequest(
                    username = username,
                    email = email,
                    password = password
                )
            )
            _registerState.value = when (result) {
                is ApiResult.Success -> {
                    // Store token in DataManager for future API calls
                    DataManager.setAuthToken(result.data.token)
                    DataManager.setCurrentUser(result.data.user)
                    ApiResult.Success(result.data)
                }
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetRegisterState() {
        _registerState.value = ApiResult.Idle
    }

    fun verifyEmail(code: String) {
        viewModelScope.launch {
            _verifyEmailState.value = ApiResult.Loading
            val token = DataManager.authToken.value ?: run {
                _verifyEmailState.value = ApiResult.Error("Not authenticated")
                return@launch
            }
            val result = APILayer.verifyEmail(token, VerifyEmailRequest(code = code))
            _verifyEmailState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetVerifyEmailState() {
        _verifyEmailState.value = ApiResult.Idle
    }

    fun updateProfile(firstName: String?, lastName: String?, email: String?) {
        viewModelScope.launch {
            _updateProfileState.value = ApiResult.Loading
            val token = DataManager.authToken.value ?: run {
                _updateProfileState.value = ApiResult.Error("Not authenticated")
                return@launch
            }
            val result = APILayer.updateProfile(
                token,
                com.tt.honeyDue.models.UpdateProfileRequest(
                    firstName = firstName,
                    lastName = lastName,
                    email = email
                )
            )
            _updateProfileState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetUpdateProfileState() {
        _updateProfileState.value = ApiResult.Idle
    }

    fun getCurrentUser(forceRefresh: Boolean = false) {
        // Fire the API call; APILayer writes through to DataManager.setCurrentUser
        // on success. [currentUserState] is a derived flow so it re-emits
        // automatically. No local state mutation needed.
        viewModelScope.launch {
            APILayer.getCurrentUser(forceRefresh = forceRefresh)
        }
    }

    /** No-op — [currentUserState] is derived from DataManager and can't be
     * locally reset. To clear, call [DataManager.setCurrentUser] with null. */
    fun resetCurrentUserState() {
        // intentionally empty
    }

    fun forgotPassword(email: String) {
        viewModelScope.launch {
            _forgotPasswordState.value = ApiResult.Loading
            val result = APILayer.forgotPassword(ForgotPasswordRequest(email = email))
            _forgotPasswordState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetForgotPasswordState() {
        _forgotPasswordState.value = ApiResult.Idle
    }

    fun verifyResetCode(email: String, code: String) {
        viewModelScope.launch {
            _verifyResetCodeState.value = ApiResult.Loading
            val result = APILayer.verifyResetCode(VerifyResetCodeRequest(email = email, code = code))
            _verifyResetCodeState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetVerifyResetCodeState() {
        _verifyResetCodeState.value = ApiResult.Idle
    }

    fun resetPassword(resetToken: String, newPassword: String, confirmPassword: String) {
        viewModelScope.launch {
            _resetPasswordState.value = ApiResult.Loading
            // Note: confirmPassword is for UI validation only, not sent to API
            val result = APILayer.resetPassword(
                ResetPasswordRequest(
                    resetToken = resetToken,
                    newPassword = newPassword
                )
            )
            _resetPasswordState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetResetPasswordState() {
        _resetPasswordState.value = ApiResult.Idle
    }

    fun appleSignIn(
        idToken: String,
        userId: String,
        email: String?,
        firstName: String?,
        lastName: String?
    ) {
        viewModelScope.launch {
            _appleSignInState.value = ApiResult.Loading
            val result = APILayer.appleSignIn(
                AppleSignInRequest(
                    idToken = idToken,
                    userId = userId,
                    email = email,
                    firstName = firstName,
                    lastName = lastName
                )
            )
            // APILayer.appleSignIn already stores token in DataManager
            _appleSignInState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetAppleSignInState() {
        _appleSignInState.value = ApiResult.Idle
    }

    fun googleSignIn(idToken: String) {
        viewModelScope.launch {
            _googleSignInState.value = ApiResult.Loading
            val result = APILayer.googleSignIn(
                GoogleSignInRequest(idToken = idToken)
            )
            // APILayer.googleSignIn already stores token in DataManager
            _googleSignInState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetGoogleSignInState() {
        _googleSignInState.value = ApiResult.Idle
    }

    fun logout() {
        viewModelScope.launch {
            // APILayer.logout clears DataManager
            APILayer.logout()
        }
    }

    fun deleteAccount(password: String?, confirmation: String?) {
        viewModelScope.launch {
            _deleteAccountState.value = ApiResult.Loading
            val result = APILayer.deleteAccount(password = password, confirmation = confirmation)
            _deleteAccountState.value = when (result) {
                is ApiResult.Success -> ApiResult.Success(result.data)
                is ApiResult.Error -> result
                else -> ApiResult.Error("Unknown error")
            }
        }
    }

    fun resetDeleteAccountState() {
        _deleteAccountState.value = ApiResult.Idle
    }
}
