package com.suno.android.ui.screens.onboarding.phone.validate import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.viewModelScope import androidx.navigation.toRoute import arrow.core.getOrElse import com.suno.android.common_core_utils.global_errors.DialogSpec import com.suno.android.common_core_utils.global_errors.TopLevelErrorManager import com.suno.android.common_core_utils.model.UiString import com.suno.android.common_data.user.UserSessionRepository import com.suno.android.common_mvi.MviProcessorFactory import com.suno.android.common_mvi.MviViewModel import com.suno.android.common_res.R import com.suno.android.framework.auth.api.AuthError import com.suno.android.framework.auth.api.AuthManager import com.suno.android.ui.screens.navigation.NavDestination import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class LoginValidatePhoneNumberScreenVM @Inject constructor( processorFactory: MviProcessorFactory, savedStateHandle: SavedStateHandle, private val authManager: AuthManager, private val topLevelErrorManager: TopLevelErrorManager, private val userSessionRepository: UserSessionRepository, ) : MviViewModel< LoginValidatePhoneNumberScreenEvent, LoginValidatePhoneNumberScreenState, LoginValidatePhoneNumberScreenEffect, >( processorFactory = processorFactory, initialState = LoginValidatePhoneNumberScreenState(), ) { private val signUpId = savedStateHandle.toRoute().signUpId private val signInId = savedStateHandle.toRoute().signInId override suspend fun reduceEvent( currentState: LoginValidatePhoneNumberScreenState, event: LoginValidatePhoneNumberScreenEvent, emitEffect: suspend (LoginValidatePhoneNumberScreenEffect) -> Unit, ): LoginValidatePhoneNumberScreenState = when (event) { is LoginValidatePhoneNumberScreenEvent.OnVerificationCodeEnteredEvent -> { currentState.copy(smsCode = event.verificationCode) } is LoginValidatePhoneNumberScreenEvent.OnVerificationCodeSubmitted -> { viewModelScope.launch { if (signUpId != null) { val response = authManager.attemptVerifyPhoneSignUp( signupId = signUpId, verificationCode = event.verificationCode, ).getOrElse { error -> handleError(error) return@launch } logger.println { response } authManager.setSessionFromPhoneNumber(response.createdSessionId) userSessionRepository.refreshUserSessionConfiguration() emitEffect(LoginValidatePhoneNumberScreenEffect.OnPhoneCodeValidated(isSignUpFlow = true)) } if (signInId != null) { val response = authManager.attemptVerifyPhoneSignIn( signInId = signInId, verificationCode = event.verificationCode, ).getOrElse { error -> handleError(error) return@launch } logger.println { response } authManager.setSessionFromPhoneNumber(response.createdSessionId) userSessionRepository.refreshUserSessionConfiguration() emitEffect(LoginValidatePhoneNumberScreenEffect.OnPhoneCodeValidated(isSignUpFlow = false)) } } currentState.copy(loading = true) } } private suspend fun handleError( error: AuthError, ) { logger.e(error.toThrowable()) updateState { it.copy(loading = false) } topLevelErrorManager.broadcastTopLevelDialogError( errorMessage = DialogSpec( title = UiString.Resource(R.string.invalid_verification_code), body = UiString.Resource(R.string.check_code_try_again), buttons = persistentListOf( DialogSpec.Button( label = UiString.Resource(R.string.ok), type = DialogSpec.Button.DialogButtonType.DEFAULT, ), ), ), ) } }