package com.suno.android.clip import arrow.core.Either import arrow.retrofit.adapter.either.networkhandling.CallError import com.suno.android.common_core_utils.Id import com.suno.android.common_core_utils.SunoLogger import com.suno.android.common_core_utils.constants.ReactionType import com.suno.android.common_data.mappers.clips.SongListData import com.suno.android.common_data.metadata.RecommendationMetadata import com.suno.android.common_data.metadata.toRemoteMetadata import com.suno.android.common_networking.extensions.toThrowable import com.suno.android.common_networking.remote.entities.RemoteUpdateReactionBody import com.suno.android.common_networking.remote.gen.GenService import com.suno.android.media.MediaMetadataManager import com.suno.android.media.MediaReaction import javax.inject.Inject private const val REMOTE_LIKE_VALUE = "L" private const val REMOTE_DISLIKE_VALUE = "D" /** * Use-case for updating clip reactions (like/dislike). */ class UpdateClipReactionUseCase @Inject constructor( loggerFactory: SunoLogger.Factory, private val genService: GenService, private val mediaMetadataManager: MediaMetadataManager, ) { private val logger = loggerFactory.create(this@UpdateClipReactionUseCase) suspend operator fun invoke( clipId: Id, currentReactionType: ReactionType?, requestedReactionType: ReactionType, recommendationMetadata: RecommendationMetadata? = null, ): Either { val body = if (currentReactionType == requestedReactionType) { RemoteUpdateReactionBody(reaction = null) } else { val requestedReaction = when (requestedReactionType) { ReactionType.LIKE -> RemoteUpdateReactionBody.Reaction.LIKE ReactionType.DISLIKE -> RemoteUpdateReactionBody.Reaction.DISLIKE ReactionType.NOTHING -> null } RemoteUpdateReactionBody( reaction = requestedReaction, recommendationMetadata = recommendationMetadata?.toRemoteMetadata(), ) } val result = genService.updateReactionType(clipId.value, body) return result.map { remoteClipReaction -> when (remoteClipReaction.reactionType) { REMOTE_LIKE_VALUE -> ReactionType.LIKE REMOTE_DISLIKE_VALUE -> ReactionType.DISLIKE else -> null }.also { updatedReaction -> broadcastReaction(clipId, updatedReaction) } }.mapLeft { error -> logger.e(error.toThrowable()) { "Failed to update reaction" } error } } private suspend fun broadcastReaction( clipId: Id, reactionType: ReactionType?, ) { val mediaReaction = MediaReaction(clipId, reactionType) mediaMetadataManager.broadcastMediaReaction(mediaReaction) } }