package com.fabledsword.minstrel.cache.db.dao

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import com.fabledsword.minstrel.cache.db.entities.CachedHomeIndexEntity
import kotlinx.coroutines.flow.Flow

@Dao
interface CachedHomeIndexDao {
    @Query(
        "SELECT * FROM cached_home_index " +
            "WHERE section = :section ORDER BY position ASC",
    )
    fun observeBySection(section: String): Flow<List<CachedHomeIndexEntity>>

    @Query(
        "SELECT * FROM cached_home_index " +
            "WHERE section = :section ORDER BY position ASC",
    )
    suspend fun getBySection(section: String): List<CachedHomeIndexEntity>

    /** True when Home has any cached section rows to render. */
    @Query("SELECT EXISTS(SELECT 1 FROM cached_home_index)")
    suspend fun hasAny(): Boolean

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun upsertAll(rows: List<CachedHomeIndexEntity>)

    @Query("DELETE FROM cached_home_index WHERE section IN (:sections)")
    suspend fun deleteSections(sections: List<String>)

    /**
     * Swaps every listed section's rows in ONE transaction.
     *
     * Atomicity is the point, not just tidiness: Room's
     * InvalidationTracker only notifies observers after the transaction
     * commits, so [observeBySection] never sees the empty gap between the
     * delete and the re-insert. Replacing sections one at a time (and
     * un-transacted) made each Home row emit `emptyList()` — visibly
     * collapsing — before refilling, and made the seven sections do it in
     * sequence rather than as a single content swap.
     */
    @Transaction
    suspend fun replaceSections(sections: List<String>, rows: List<CachedHomeIndexEntity>) {
        deleteSections(sections)
        if (rows.isNotEmpty()) upsertAll(rows)
    }

    @Query("DELETE FROM cached_home_index")
    suspend fun clear()
}
