package com.fabledsword.minstrel.cache

import com.fabledsword.minstrel.di.ApplicationScope
import com.fabledsword.minstrel.player.PlayerController
import com.fabledsword.minstrel.player.PlayerFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Reactive set of track ids that have audio bytes in the Media3
 * [SimpleCache][PlayerFactory.simpleCache], used to drive the cached
 * indicator dot on track rows.
 *
 * The SimpleCache (keyed per track via the MediaItem custom cache key)
 * is the source of truth for true on-disk residency — querying it
 * directly, rather than trusting an index row, means an evicted track
 * loses its dot. The key set is read on the IO dispatcher (it scans
 * cache metadata) and re-read on every track change, since playback is
 * what grows the incidental cache.
 *
 * The persisted SimpleCache survives process death, so the eager
 * initial read paints dots for previously-cached tracks even when the
 * library is opened offline with no active playback.
 */
@Singleton
class CachedTrackIds @Inject constructor(
    playerController: PlayerController,
    private val playerFactory: PlayerFactory,
    @ApplicationScope scope: CoroutineScope,
) {
    private val refresh = MutableStateFlow(0L)

    val ids: StateFlow<Set<String>> =
        refresh
            .map { readKeys() }
            .flowOn(Dispatchers.IO)
            .stateIn(scope, SharingStarted.Eagerly, emptySet())

    init {
        scope.launch {
            playerController.uiState
                .map { it.currentTrack?.id }
                .distinctUntilChanged()
                .collect { refresh.value += 1 }
        }
    }

    private fun readKeys(): Set<String> =
        runCatching { playerFactory.simpleCache.keys.toSet() }.getOrDefault(emptySet())
}
