package com.suno.android.common_data.generation import com.suno.android.common_core_utils.Id import com.suno.android.common_data.mappers.clips.ClipStatus import com.suno.android.common_data.mappers.clips.SongListData import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import javax.inject.Inject interface SongGenerationStateStore { fun songGenerationStateFlow(): StateFlow fun songGenerationEffectsFlow(): Flow fun upsertClips( clipStatuses: Map, ClipStatus>, ) fun removeClips( clipIds: Set>, ) } class SongGenerationStoreImpl @Inject constructor() : SongGenerationStateStore { private val _songGenerationStateFlow = MutableStateFlow(SongGenerationState()) override fun songGenerationStateFlow(): StateFlow = _songGenerationStateFlow.asStateFlow() private val _songGenerationEffects = MutableSharedFlow() override fun songGenerationEffectsFlow(): Flow = _songGenerationEffects.asSharedFlow() override fun upsertClips( clipStatuses: Map, ClipStatus>, ) { if (clipStatuses.isEmpty()) return _songGenerationStateFlow.update { oldState -> oldState.copy( clipStatuses = (oldState.clipStatuses + clipStatuses).toImmutableMap(), ) } } override fun removeClips( clipIds: Set>, ) { if (clipIds.isEmpty()) return _songGenerationStateFlow.update { oldState -> oldState.copy( clipStatuses = (oldState.clipStatuses - clipIds).toImmutableMap(), ) } } data class SongGenerationState( val clipStatuses: ImmutableMap, ClipStatus> = persistentMapOf(), ) { val generatingClipIds: Set> by lazy { clipStatuses.filterValues { it.isGenerating }.keys } val readyClipIds: Set> by lazy { clipStatuses.filterValues { it.isReady }.keys } val nonTerminalClipIds: Set> by lazy { clipStatuses.filterValues { !it.isTerminal }.keys } } sealed interface SongGenerationEffects { data class Error( val reason: String, ) : SongGenerationEffects } }