package com.fabledsword.minstrel.shared.widgets

import androidx.compose.runtime.Stable
import androidx.compose.runtime.staticCompositionLocalOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update

/**
 * Counts the cover-art loads that are currently in flight, so a
 * screen-level overlay can wait for the artwork to actually land instead
 * of guessing with a fixed delay.
 *
 * Artwork is the most visible pop-in on Home: a tile can be fully
 * hydrated (title, artist, counts all present) and still snap its cover
 * in a second later, which is exactly the churn the "Updating your
 * mixes…" veil exists to hide. The refresh coroutine can't see that —
 * it finishes long before Coil does — so the composition reports it
 * upward here instead.
 *
 * [ServerImage] reports into whatever tracker it finds in
 * [LocalArtSettleTracker], which means every art surface in the app
 * participates for free. Only *composed* images are counted, so a
 * LazyRow's off-screen tiles are correctly ignored — the count tracks
 * the pop-in a user can actually see.
 *
 * Provide one per screen that needs it (typically owned by the
 * screen's ViewModel so its refresh logic can read [inFlight]):
 *
 *     CompositionLocalProvider(LocalArtSettleTracker provides vm.artTracker) { ... }
 */
@Stable
class ArtSettleTracker {
    private val inFlightInternal = MutableStateFlow(0)

    /**
     * How many on-screen images are still loading. Zero means the
     * artwork has settled — every composed cover has either drawn or
     * failed to a fallback.
     */
    val inFlight: StateFlow<Int> = inFlightInternal.asStateFlow()

    fun begin() {
        inFlightInternal.update { it + 1 }
    }

    fun end() {
        // Floor at zero: a decrement can outlive its increment when a
        // tile is disposed mid-load and the count must not go negative
        // and wedge "settled" off forever.
        inFlightInternal.update { (it - 1).coerceAtLeast(0) }
    }
}

/**
 * The tracker [ServerImage] reports load state to, or null on screens
 * that don't care (the default) — reporting is then a no-op.
 */
val LocalArtSettleTracker = staticCompositionLocalOf<ArtSettleTracker?> { null }
