package com.suno.android.ui.screens.create.audio.precondition import com.suno.android.common_core_utils.environment.UserPrefsDataStoreManager 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_mvi.MviController import com.suno.android.common_mvi.MviProcessorFactory import com.suno.android.common_res.R import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch class AudioPreconditionController @AssistedInject constructor( processorFactory: MviProcessorFactory, @Assisted coroutineScope: CoroutineScope, @Assisted val flow: Flow, @Assisted val onAllPreconditionsComplete: () -> Unit, private val userPrefsDataStoreManager: UserPrefsDataStoreManager, private val topLevelErrorManager: TopLevelErrorManager, private val getPreconditionStatusUseCase: GetPreconditionStatusUseCase, ) : MviController( processorFactory = processorFactory, coroutineScope = coroutineScope, initialState = AudioPreconditionState( flow = flow, preconditions = flow.preconditions, preconditionStates = emptyMap(), ), ) { enum class Flow( val preconditions: ImmutableList, ) { Upload( persistentListOf( AudioPreconditionState.Precondition.TermsOfService, ), ), Record( persistentListOf( AudioPreconditionState.Precondition.RecordingPermission, AudioPreconditionState.Precondition.TermsOfService, ), ), } @AssistedFactory interface Factory { fun create( coroutineScope: CoroutineScope, flow: Flow, onAllPreconditionsComplete: () -> Unit, ): AudioPreconditionController } init { controllerScope.launch { val states = getPreconditionStatusUseCase(flow.preconditions) updateState { currentState -> currentState.copy( preconditionStates = states, ) } } } override suspend fun reduceEvent( currentState: AudioPreconditionState, event: AudioPreconditionEvent, emitEffect: suspend (AudioPreconditionEffect) -> Unit, ): AudioPreconditionState = when (event) { is AudioPreconditionEvent.OnAcceptPrecondition -> { onAcceptPrecondition(event.precondition) currentState } AudioPreconditionEvent.ShowTosDialog -> { showTosDialog() currentState } AudioPreconditionEvent.OnRecordingPermissionAccepted -> currentState.copy( preconditionStates = currentState.preconditionStates + (AudioPreconditionState.Precondition.RecordingPermission to true), ) } private val completeAllConditionsJob = state.onEach { state -> val areAllComplete = state.preconditions.all { precondition -> state.preconditionStates[precondition] == true } if (areAllComplete) { onAllPreconditionsComplete() } }.launchIn(controllerScope) private suspend fun showTosDialog() { topLevelErrorManager.broadcastTopLevelDialogError( DialogSpec( title = UiString.Resource(R.string.audio_terms_of_service_title), body = UiString.Resource(R.string.audio_terms_of_service_body), buttons = persistentListOf( DialogSpec.Button( label = UiString.Resource(R.string.audio_terms_of_service_decline), onClick = { dismiss -> dismiss() }, ), DialogSpec.Button( label = UiString.Resource(R.string.audio_terms_of_service_accept), onClick = { dismiss -> controllerScope.launch { userPrefsDataStoreManager.setHasAcceptedAudioUploadTerms() updateState { currentState -> currentState.copy( preconditionStates = currentState.preconditionStates + (AudioPreconditionState.Precondition.TermsOfService to true), ) } dismiss() } }, ), ), ), ) } private suspend fun onAcceptPrecondition( precondition: AudioPreconditionState.Precondition, ) = when (precondition) { AudioPreconditionState.Precondition.TermsOfService -> showTosDialog() AudioPreconditionState.Precondition.RecordingPermission -> emitEffect( AudioPreconditionEffect.RequestRecordingPermission, ) } }