package com.suno.android.common_data.managers import android.net.Uri import com.suno.android.common_core_utils.ApplicationCoroutineScope import com.suno.android.common_core_utils.Id import com.suno.android.common_core_utils.SunoLogger import com.suno.android.common_core_utils.model.Url import com.suno.android.common_core_utils.model.UserHandle import com.suno.android.common_data.mappers.hooks.LocalHookData import com.suno.android.common_data.use_case.DownloadHookUseCase import com.suno.android.common_data.use_case.HookDownloadError import kotlinx.coroutines.CoroutineScope 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 import javax.inject.Singleton interface HookDownloadManager { fun downloadStateFlow(): StateFlow fun startDownload( hook: LocalHookData, ) sealed interface HookDownloadState { data object Idle : HookDownloadState data class Downloading( val hookId: Id, val hookCreatorHandle: UserHandle?, ) : HookDownloadState data class Complete( val hookId: Id, val hookCreatorHandle: UserHandle?, val hookPreviewUrl: Url?, val localVideoUri: Uri?, ) : HookDownloadState data class Error( val hookId: Id, val error: HookDownloadError, ) : HookDownloadState } } @Singleton class HookDownloadManagerImpl @Inject constructor( loggerFactory: SunoLogger.Factory, private val downloadHookUseCase: DownloadHookUseCase, @ApplicationCoroutineScope private val coroutineScope: CoroutineScope, ) : HookDownloadManager { private val logger = loggerFactory.create(this@HookDownloadManagerImpl) private val _downloadStateFlow = MutableStateFlow( HookDownloadManager.HookDownloadState.Idle, ) override fun downloadStateFlow(): StateFlow = _downloadStateFlow.asStateFlow() override fun startDownload( hook: LocalHookData, ) { _downloadStateFlow.update { HookDownloadManager.HookDownloadState.Downloading( hookId = hook.hookId, hookCreatorHandle = hook.creator.handle, ) } coroutineScope.launch { val result = downloadHookUseCase(hook) result.fold( ifLeft = { error -> logger.w { "Download failed: $error" } _downloadStateFlow.update { HookDownloadManager.HookDownloadState.Error(hook.hookId, error) } }, ifRight = { downloadResult -> _downloadStateFlow.update { HookDownloadManager.HookDownloadState.Complete( hookId = downloadResult.hookId, hookPreviewUrl = downloadResult.hookPreviewUrl, hookCreatorHandle = hook.creator.handle, localVideoUri = downloadResult.videoUri, ) } }, ) } } }