package app.closer.data.remote

import app.closer.domain.model.ActivityItem
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.Query
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Reads the user's "Together" activity feed from `users/{uid}/notification_queue`.
 * The queue is written server-side (Admin SDK); the client only reads and flips `read`.
 */
@Singleton
class FirestoreActivityDataSource @Inject constructor(
    private val db: FirebaseFirestore
) {
    private fun queueRef(userId: String) =
        db.collection("users").document(userId).collection("notification_queue")

    /** Live activity feed, newest first. Errors are swallowed so the flow never crashes. */
    fun observeActivity(userId: String): Flow<List<ActivityItem>> = callbackFlow {
        val reg = queueRef(userId)
            .orderBy("createdAt", Query.Direction.DESCENDING)
            .limit(50)
            .addSnapshotListener { snap, err ->
                // Resolve to an empty feed on error (e.g. rules) rather than hanging on loading.
                if (err != null) { trySend(emptyList()); return@addSnapshotListener }
                if (snap == null) return@addSnapshotListener
                trySend(snap.documents.map { d ->
                    ActivityItem(
                        id = d.id,
                        type = d.getString("type") ?: "",
                        title = d.getString("title") ?: "",
                        body = d.getString("body") ?: "",
                        read = d.getBoolean("read") ?: false,
                        createdAt = d.getTimestamp("createdAt")?.toDate()?.time
                            ?: (d.getLong("createdAt") ?: 0L)
                    )
                })
            }
        awaitClose { reg.remove() }
    }

    /** Live count of unread activity items (0 on error, so the badge fails closed). */
    fun observeUnreadCount(userId: String): Flow<Int> = callbackFlow {
        val reg = queueRef(userId)
            .whereEqualTo("read", false)
            .addSnapshotListener { snap, err ->
                if (err != null) { trySend(0); return@addSnapshotListener }
                trySend(snap?.size() ?: 0)
            }
        awaitClose { reg.remove() }
    }

    /** Marks every unread item read. Best-effort. */
    suspend fun markAllRead(userId: String) {
        val unread = queueRef(userId).whereEqualTo("read", false).get().await()
        if (unread.isEmpty) return
        val batch = db.batch()
        unread.documents.forEach { batch.update(it.reference, "read", true) }
        batch.commit().await()
    }
}
