package com.suno.android.common_data.alerts import arrow.core.getOrElse import com.suno.android.common_core_utils.SunoLogger import com.suno.android.common_core_utils.extensions.toFormattedUTCString import com.suno.android.common_networking.extensions.toThrowable import com.suno.android.common_networking.remote.entities.NotificationsInner import com.suno.android.common_networking.remote.entities.ReadNotificationsSpec import com.suno.android.common_networking.remote.notification.NotificationService import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import java.time.Instant import javax.inject.Inject interface AlertsRepo { fun inAppNotificationsStateFlow(): StateFlow suspend fun syncNotifications() suspend fun markNotificationsAsRead( ids: List, ) } data class InAppNotificationsState( val notifications: List? = null, val hasUnreadNotifications: Boolean = false, ) internal class AlertsRepoImpl @Inject constructor( loggerFactory: SunoLogger.Factory, private val notificationService: NotificationService, ) : AlertsRepo { private val logger = loggerFactory.create(this@AlertsRepoImpl) private val _inAppNotificationsStateFlow = MutableStateFlow(InAppNotificationsState()) override fun inAppNotificationsStateFlow() = _inAppNotificationsStateFlow.asStateFlow() private var lastSyncTime = Instant.EPOCH.toFormattedUTCString() override suspend fun syncNotifications() { logger.d { "Syncing notifications, last sync time: $lastSyncTime" } val response = notificationService.getNotifications(lastSyncTime).getOrElse { error -> logger.e(error.toThrowable()) return } _inAppNotificationsStateFlow.update { oldState -> val currentNotifications = oldState.notifications ?: emptyList() val updatedNotifications = currentNotifications + response.notifications createNotificationsState(updatedNotifications) } lastSyncTime = response.notifiedAt } override suspend fun markNotificationsAsRead( ids: List, ) { notificationService.markNotificationsAsRead(ReadNotificationsSpec(ids)).getOrElse { error -> logger.e(error.toThrowable()) return } _inAppNotificationsStateFlow.update { oldState -> val currentNotifications = oldState.notifications ?: return@update oldState val updatedNotifications = currentNotifications.map { notification -> if (ids.contains(notification.id)) { notification.copy(isRead = true) } else { notification } } createNotificationsState(updatedNotifications) } logger.d { "Marked notifications as read: $ids" } } private fun createNotificationsState( updatedNotifications: List, ): InAppNotificationsState { val hasUnreadNotifications = updatedNotifications.any { it.isRead == false } return InAppNotificationsState( notifications = updatedNotifications, hasUnreadNotifications = hasUnreadNotifications, ) } }