package com.fabledsword.minstrel.player.ui

import androidx.compose.animation.animateColorAsState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.palette.graphics.Palette
import coil3.SingletonImageLoader
import coil3.request.ImageRequest
import coil3.request.SuccessResult
import coil3.request.allowHardware
import coil3.toBitmap
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

private const val GRADIENT_TWEEN_MS = 600

/**
 * Animated dominant-color extractor for the NowPlaying gradient
 * backdrop. Fetches [coverUrl] via Coil's singleton loader (so the
 * bitmap is shared with the on-screen AsyncImage cache), runs
 * androidx.palette on a background thread, and animates the result
 * via [animateColorAsState] so track changes tween smoothly.
 *
 * The held color is NOT reset when [coverUrl] changes — it stays on
 * the previous track's dominant until the new palette resolves, so the
 * gradient tweens old→new directly instead of dipping toward the
 * fallback mid-swap. Mirrors `now_playing_screen.dart`'s preload-then-
 * swap ("keep the previous dominant"); the cover image swaps smoothly
 * via `CoverPrefetcher`, which warms the next track's bytes into Coil.
 *
 * Starts at [Color.Transparent] (cold mount) and resets to it only
 * when a track has no cover — callers layer a base color underneath so
 * the screen never sits on flat black.
 */
@Composable
fun rememberDominantColor(coverUrl: String?): Color {
    val context = LocalContext.current
    var extracted by remember { mutableStateOf(Color.Transparent) }

    LaunchedEffect(coverUrl) {
        if (coverUrl.isNullOrEmpty()) {
            extracted = Color.Transparent
            return@LaunchedEffect
        }
        val request = ImageRequest.Builder(context)
            .data(coverUrl)
            .allowHardware(false)
            .build()
        val result = SingletonImageLoader.get(context).execute(request)
        // Keep the previous dominant on load failure rather than dropping.
        if (result !is SuccessResult) return@LaunchedEffect
        val bitmap = result.image.toBitmap()
        val palette = withContext(Dispatchers.Default) {
            Palette.from(bitmap).generate()
        }
        // Always use the dominant (majority-by-pixel-count) swatch.
        // The cover art is the main feature of this view; a vibrant
        // accent on the cover should pop against the background, not
        // be matched by it. Previously we tried vibrant first, which
        // picked the highest-saturation swatch even when it covered
        // a tiny fraction of the cover — small bright accents made
        // the gradient feel disconnected from the actual image.
        val swatch = palette.dominantSwatch
        if (swatch != null) {
            extracted = Color(swatch.rgb)
        }
    }

    val animated by animateColorAsState(
        targetValue = extracted,
        animationSpec = androidx.compose.animation.core.tween(GRADIENT_TWEEN_MS),
        label = "now-playing-dominant",
    )
    return animated
}
