package cy.hexor.furumi.ui.player

import android.content.Intent
import android.graphics.Bitmap
import androidx.activity.compose.BackHandler
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.GridItemSpan
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.draw.clip
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import cy.hexor.furumi.domain.model.ArtistCard
import cy.hexor.furumi.domain.model.PlaylistCard
import cy.hexor.furumi.domain.model.ReleaseCard
import cy.hexor.furumi.domain.model.TrackCard
import cy.hexor.furumi.domain.model.ListeningHistoryItem
import cy.hexor.furumi.playback.AudioPlaybackState
import cy.hexor.furumi.ui.theme.FurumiBlack
import cy.hexor.furumi.ui.theme.FurumiElectricCyan
import cy.hexor.furumi.ui.theme.FurumiHotOrange
import cy.hexor.furumi.ui.theme.FurumiLine
import cy.hexor.furumi.ui.theme.FurumiNeonPink
import cy.hexor.furumi.ui.theme.FurumiNeonViolet
import cy.hexor.furumi.ui.theme.FurumiSurface
import cy.hexor.furumi.ui.theme.FurumiSurfaceHigh
import cy.hexor.furumi.ui.theme.FurumiTextMuted
import kotlin.math.roundToInt

@Composable
internal fun SearchContent(
    uiState: PlayerUiState,
    onProfileClick: () -> Unit,
    onQueryChange: (String) -> Unit,
    onRetry: () -> Unit,
    onArtistClick: (ArtistCard) -> Unit,
    onMediaImageNeeded: (String?) -> Unit,
    onTrackClick: (TrackCard) -> Unit,
    onToggleLike: (Long) -> Unit,
    onPlayNext: (TrackCard) -> Unit,
    onPlayLast: (TrackCard) -> Unit,
    onShare: (TrackCard) -> Unit,
    onAddToPlaylist: (TrackCard) -> Unit
) {
    val query = uiState.searchQuery
    val results = uiState.searchResults
    val artists = searchArtists(uiState)
    val tracks = results?.tracks.orEmpty()

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 20.dp, vertical = 24.dp)
    ) {
        PlayerHeader(title = "Search", subtitle = "Find music on your server", onProfileClick = onProfileClick)
        Spacer(modifier = Modifier.height(18.dp))
        TextField(
            value = query,
            onValueChange = onQueryChange,
            modifier = Modifier
                .fillMaxWidth()
                .height(54.dp),
            shape = RoundedCornerShape(8.dp),
            singleLine = true,
            placeholder = {
                Text(
                    text = "Artists and tracks",
                    style = MaterialTheme.typography.bodyLarge
                )
            },
            leadingIcon = {
                SearchGlyph(
                    modifier = Modifier.size(22.dp),
                    color = FurumiBlack
                )
            }
        )

        Spacer(modifier = Modifier.height(22.dp))

        when {
            query.isBlank() -> SearchEmptyPrompt()
            uiState.isSearchLoading && results == null -> SearchLoading()
            uiState.searchError != null && results == null -> SearchError(
                message = uiState.searchError,
                onRetry = onRetry
            )
            artists.isEmpty() && tracks.isEmpty() && !uiState.isSearchLoading -> SearchNoResults()
            else -> {
                if (artists.isNotEmpty()) {
                    SearchArtistsSection(
                        artists = artists,
                        mediaImages = uiState.mediaImages,
                        onMediaImageNeeded = onMediaImageNeeded,
                        onArtistClick = onArtistClick
                    )
                    Spacer(modifier = Modifier.height(26.dp))
                }

                if (tracks.isNotEmpty()) {
                    SearchTracksSection(
                        tracks = tracks,
                        mediaImages = uiState.mediaImages,
                        likedTrackIds = uiState.likedTrackIds,
                        onMediaImageNeeded = onMediaImageNeeded,
                        onTrackClick = onTrackClick,
                        onToggleLike = onToggleLike,
                        onPlayNext = onPlayNext,
                        onPlayLast = onPlayLast,
                        onShare = onShare,
                        onAddToPlaylist = onAddToPlaylist
                    )
                }

                if (uiState.isSearchLoading) {
                    Spacer(modifier = Modifier.height(20.dp))
                    CircularProgressIndicator(
                        color = FurumiNeonPink,
                        strokeWidth = 2.dp,
                        modifier = Modifier
                            .size(24.dp)
                            .align(Alignment.CenterHorizontally)
                    )
                }
            }
        }
    }
}

@Composable
private fun SearchArtistsSection(
    artists: List<ArtistCard>,
    mediaImages: Map<String, Bitmap>,
    onMediaImageNeeded: (String?) -> Unit,
    onArtistClick: (ArtistCard) -> Unit
) {
    SectionTitle("Artists")
    Spacer(modifier = Modifier.height(12.dp))
    Row(
        modifier = Modifier.horizontalScroll(rememberScrollState()),
        horizontalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        artists.forEach { artist ->
            SearchArtistCard(
                artist = artist,
                bitmap = mediaImageFor(mediaImages, artist.imageUrl),
                onMediaImageNeeded = onMediaImageNeeded,
                onClick = { onArtistClick(artist) }
            )
        }
    }
}

@Composable
private fun SearchArtistCard(
    artist: ArtistCard,
    bitmap: Bitmap?,
    onMediaImageNeeded: (String?) -> Unit,
    onClick: () -> Unit
) {
    LaunchedEffect(artist.imageUrl) {
        onMediaImageNeeded(artist.imageUrl)
    }

    Column(
        modifier = Modifier
            .width(104.dp)
            .clip(RoundedCornerShape(8.dp))
            .clickable(onClick = onClick)
    ) {
        MediaArtwork(
            title = artist.name,
            seedId = artist.id,
            bitmap = bitmap,
            modifier = Modifier.size(104.dp),
            cornerRadius = 8
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(
            text = artist.name,
            style = MaterialTheme.typography.labelLarge,
            color = MaterialTheme.colorScheme.onBackground,
            maxLines = 2,
            overflow = TextOverflow.Ellipsis
        )
    }
}

@Composable
private fun SearchTracksSection(
    tracks: List<TrackCard>,
    mediaImages: Map<String, Bitmap>,
    likedTrackIds: Set<Long>,
    onMediaImageNeeded: (String?) -> Unit,
    onTrackClick: (TrackCard) -> Unit,
    onToggleLike: (Long) -> Unit,
    onPlayNext: (TrackCard) -> Unit,
    onPlayLast: (TrackCard) -> Unit,
    onShare: (TrackCard) -> Unit,
    onAddToPlaylist: (TrackCard) -> Unit
) {
    SectionTitle("Tracks")
    Spacer(modifier = Modifier.height(12.dp))
    Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
        tracks.forEachIndexed { index, track ->
            PlaylistTrackRow(
                index = index + 1,
                track = track,
                bitmap = mediaImageFor(mediaImages, track.coverUrl),
                isLiked = likedTrackIds.contains(track.id),
                onMediaImageNeeded = onMediaImageNeeded,
                onTrackClick = onTrackClick,
                onToggleLike = { onToggleLike(track.id) },
                onPlayNext = { onPlayNext(track) },
                onPlayLast = { onPlayLast(track) },
                onShare = { onShare(track) },
                onAddToPlaylist = { onAddToPlaylist(track) }
            )
        }
    }
}

@Composable
private fun SearchEmptyPrompt() {
    Text(
        text = "Start typing to search artists and tracks.",
        style = MaterialTheme.typography.bodyMedium,
        color = FurumiTextMuted
    )
}

@Composable
private fun SearchLoading() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(180.dp),
        contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator(
            color = FurumiNeonPink,
            strokeWidth = 2.dp
        )
    }
}

@Composable
private fun SearchError(
    message: String,
    onRetry: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = "Could not search",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.height(6.dp))
            Text(
                text = message,
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
            Spacer(modifier = Modifier.height(14.dp))
            PillAction(
                label = "Retry",
                selected = true,
                onClick = onRetry
            )
        }
    }
}

@Composable
private fun SearchNoResults() {
    Text(
        text = "No matches found",
        style = MaterialTheme.typography.bodyMedium,
        color = FurumiTextMuted
    )
}

private fun searchArtists(uiState: PlayerUiState): List<ArtistCard> {
    val results = uiState.searchResults ?: return emptyList()
    return (results.artistMatches + results.trackArtists).distinctBy { it.id }
}

@Composable
internal fun LibraryContent(
    uiState: PlayerUiState,
    onProfileClick: () -> Unit,
    onLoadLibrary: () -> Unit,
    onRetryPlaylists: () -> Unit,
    onRetryArtists: () -> Unit,
    onLoadMoreArtists: () -> Unit,
    onCreatePlaylistClick: () -> Unit,
    onPlaylistPreviewNeeded: (PlaylistCard) -> Unit,
    onPlaylistClick: (PlaylistCard) -> Unit,
    onArtistImageNeeded: (String?) -> Unit,
    onArtistClick: (ArtistCard) -> Unit
) {
    LaunchedEffect(Unit) {
        onLoadLibrary()
    }

    val playlists = orderedLibraryPlaylists(uiState.playlists)

    LazyVerticalGrid(
        columns = GridCells.Adaptive(minSize = 148.dp),
        modifier = Modifier
            .fillMaxSize(),
        contentPadding = PaddingValues(horizontal = 20.dp, vertical = 24.dp),
        horizontalArrangement = Arrangement.spacedBy(14.dp),
        verticalArrangement = Arrangement.spacedBy(18.dp)
    ) {
        item(span = { GridItemSpan(maxLineSpan) }) {
            PlayerHeader(
                title = "Your Library",
                subtitle = librarySubtitle(uiState),
                onProfileClick = onProfileClick
            )
        }

        item(span = { GridItemSpan(maxLineSpan) }) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.SpaceBetween
            ) {
                SectionTitle("Playlists")
                Surface(
                    modifier = Modifier
                        .size(36.dp)
                        .clip(CircleShape)
                        .clickable(onClick = onCreatePlaylistClick),
                    shape = CircleShape,
                    color = FurumiNeonPink
                ) {
                    Box(contentAlignment = Alignment.Center) {
                        PlusGlyph(Modifier.size(16.dp), FurumiBlack)
                    }
                }
            }
        }

        when {
            uiState.isPlaylistsLoading && playlists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryLoading()
                }
            }

            uiState.playlistsError != null && playlists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryError(
                        message = uiState.playlistsError,
                        onRetry = onRetryPlaylists
                    )
                }
            }

            playlists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryEmpty()
                }
            }

            else -> {
                items(
                    items = playlists,
                    key = { playlist -> "playlist-${playlist.id}-${playlist.title}" }
                ) { playlist ->
                    PlaylistTile(
                        playlist = playlist,
                        coverUrls = uiState.playlistPreviewCoverUrls[playlist.id].orEmpty(),
                        mediaImages = uiState.mediaImages,
                        onPlaylistPreviewNeeded = onPlaylistPreviewNeeded,
                        onClick = { onPlaylistClick(playlist) }
                    )
                }
            }
        }

        item(span = { GridItemSpan(maxLineSpan) }) {
            Text(
                text = "Artists",
                modifier = Modifier.padding(top = 8.dp),
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
        }

        when {
            uiState.isLibraryArtistsLoading && uiState.libraryArtists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryLoading()
                }
            }

            uiState.libraryArtistsError != null && uiState.libraryArtists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryArtistsError(
                        message = uiState.libraryArtistsError,
                        onRetry = onRetryArtists
                    )
                }
            }

            uiState.libraryArtists.isEmpty() -> {
                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryArtistsEmpty()
                }
            }

            else -> {
                items(
                    items = uiState.libraryArtists,
                    key = { artist -> "artist-${artist.id}" }
                ) { artist ->
                    ArtistTile(
                        artist = artist,
                        bitmap = mediaImageFor(uiState.mediaImages, artist.imageUrl),
                        onArtistImageNeeded = onArtistImageNeeded,
                        onClick = { onArtistClick(artist) }
                    )
                }

                item(span = { GridItemSpan(maxLineSpan) }) {
                    LibraryArtistsFooter(
                        uiState = uiState,
                        onLoadMore = onLoadMoreArtists
                    )
                }
            }
        }
    }
}

@Composable
private fun PlaylistTile(
    playlist: PlaylistCard,
    coverUrls: List<String>,
    mediaImages: Map<String, Bitmap>,
    onPlaylistPreviewNeeded: (PlaylistCard) -> Unit,
    onClick: () -> Unit
) {
    LaunchedEffect(playlist.id) {
        if (!playlist.isLikesPlaylist()) {
            onPlaylistPreviewNeeded(playlist)
        }
    }

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(8.dp))
            .clickable(onClick = onClick)
    ) {
        PlaylistArtwork(
            playlist = playlist,
            coverUrls = coverUrls,
            mediaImages = mediaImages,
            modifier = Modifier
                .fillMaxWidth()
                .aspectRatio(1f),
            cornerRadius = 8
        )
        Spacer(modifier = Modifier.height(10.dp))
        Text(
            text = playlist.title,
            style = MaterialTheme.typography.labelLarge,
            color = MaterialTheme.colorScheme.onBackground,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
        Spacer(modifier = Modifier.height(2.dp))
        Text(
            text = playlistMeta(playlist),
            style = MaterialTheme.typography.bodyMedium,
            color = FurumiTextMuted,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
    }
}

@Composable
private fun PlaylistArtwork(
    playlist: PlaylistCard,
    coverUrls: List<String>,
    mediaImages: Map<String, Bitmap>,
    modifier: Modifier,
    cornerRadius: Int
) {
    val artworkShape = RoundedCornerShape(cornerRadius.dp)
    val miniArtworkShape = RoundedCornerShape(5.dp)

    if (playlist.isLikesPlaylist()) {
        Box(
            modifier = modifier
                .clip(artworkShape)
                .background(Brush.linearGradient(listOf(FurumiSurfaceHigh, FurumiNeonViolet, FurumiBlack))),
            contentAlignment = Alignment.Center
        ) {
            HeartGlyph(
                isLiked = true,
                modifier = Modifier.size(86.dp)
            )
        }
        return
    }

    val previewCoverUrls = coverUrls.take(4)
    if (previewCoverUrls.isEmpty()) {
        AlbumArtwork(
            colors = playlistArtworkColors(playlist),
            modifier = modifier,
            cornerRadius = cornerRadius
        )
        return
    }

    Box(
        modifier = modifier
            .clip(artworkShape)
            .background(FurumiSurfaceHigh)
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(2.dp),
            verticalArrangement = Arrangement.spacedBy(2.dp)
        ) {
            repeat(2) { row ->
                Row(
                    modifier = Modifier.weight(1f),
                    horizontalArrangement = Arrangement.spacedBy(2.dp)
                ) {
                    repeat(2) { column ->
                        val slotIndex = row * 2 + column
                        val coverUrl = previewCoverUrls.getOrNull(slotIndex)
                        val bitmap = coverUrl?.let { mediaImageFor(mediaImages, it) }
                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .fillMaxHeight()
                                .clip(miniArtworkShape)
                                .background(Brush.linearGradient(artistArtworkColors(playlist.id + slotIndex)))
                        ) {
                            if (bitmap != null) {
                                Image(
                                    bitmap = bitmap.asImageBitmap(),
                                    contentDescription = "${playlist.title} cover ${slotIndex + 1}",
                                    modifier = Modifier.fillMaxSize(),
                                    contentScale = ContentScale.Crop
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

@Composable
internal fun PlaylistDetailContent(
    uiState: PlayerUiState,
    onBack: () -> Unit,
    onRetry: () -> Unit,
    onMediaImageNeeded: (String?) -> Unit,
    onPlayClick: () -> Unit,
    onShuffleClick: () -> Unit,
    onTrackClick: (TrackCard) -> Unit,
    onToggleLike: (Long) -> Unit,
    onPlayNext: (TrackCard) -> Unit,
    onPlayLast: (TrackCard) -> Unit,
    onShare: (TrackCard) -> Unit,
    onAddToPlaylist: (TrackCard) -> Unit,
    onDeletePlaylistClick: (PlaylistCard) -> Unit
) {
    val playlist = uiState.playlistDetail?.playlist ?: uiState.selectedPlaylist ?: return
    val tracks = uiState.playlistDetail?.tracks.orEmpty()
    val heroTrack = tracks.firstOrNull { !it.coverUrl.isNullOrBlank() }
    val heroImage = mediaImageFor(uiState.mediaImages, heroTrack?.coverUrl)

    LaunchedEffect(heroTrack?.coverUrl) {
        onMediaImageNeeded(heroTrack?.coverUrl)
    }

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 20.dp, vertical = 20.dp)
    ) {
        Row(
            modifier = Modifier
                .clip(RoundedCornerShape(8.dp))
                .clickable(onClick = onBack)
                .padding(vertical = 8.dp, horizontal = 2.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            BackGlyph(
                modifier = Modifier.size(20.dp),
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.width(8.dp))
            Text(
                text = "Playlist",
                style = MaterialTheme.typography.labelLarge,
                color = MaterialTheme.colorScheme.onBackground
            )
        }

        Spacer(modifier = Modifier.height(20.dp))

        MediaArtwork(
            title = playlist.title,
            seedId = playlist.id,
            bitmap = heroImage,
            modifier = Modifier
                .size(190.dp)
                .align(Alignment.CenterHorizontally),
            cornerRadius = 10
        )

        Spacer(modifier = Modifier.height(22.dp))

        Text(
            text = playlist.title,
            style = MaterialTheme.typography.headlineMedium,
            color = MaterialTheme.colorScheme.onBackground
        )
        Spacer(modifier = Modifier.height(6.dp))
        uiState.playlistDetail?.description
            ?.takeIf { it.isNotBlank() }
            ?.let { description ->
                Text(
                    text = description,
                    style = MaterialTheme.typography.bodyMedium,
                    color = FurumiTextMuted
                )
                Spacer(modifier = Modifier.height(6.dp))
            }
        Spacer(modifier = Modifier.height(10.dp))
        Text(
            text = playlistMeta(playlist),
            style = MaterialTheme.typography.labelSmall,
            color = FurumiTextMuted
        )

        Spacer(modifier = Modifier.height(18.dp))

        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically
        ) {
            PillAction(
                label = "Play",
                selected = true,
                modifier = Modifier.weight(1f),
                onClick = onPlayClick
            )
            Spacer(modifier = Modifier.width(12.dp))
            PillAction(
                label = "Shuffle",
                selected = false,
                modifier = Modifier.weight(1f),
                onClick = onShuffleClick
            )
        }

        if (playlist.canDeleteFromDetail()) {
            Spacer(modifier = Modifier.height(12.dp))
            OutlinedButton(
                onClick = { onDeletePlaylistClick(playlist) },
                modifier = Modifier
                    .fillMaxWidth()
                    .height(44.dp),
                shape = CircleShape,
                border = androidx.compose.foundation.BorderStroke(1.dp, FurumiHotOrange.copy(alpha = 0.72f)),
                colors = ButtonDefaults.outlinedButtonColors(
                    contentColor = FurumiHotOrange,
                    disabledContentColor = FurumiTextMuted
                )
            ) {
                Text("Delete playlist")
            }
        }

        Spacer(modifier = Modifier.height(24.dp))

        when {
            uiState.isPlaylistDetailLoading && uiState.playlistDetail == null -> PlaylistDetailLoading()
            uiState.playlistDetailError != null && uiState.playlistDetail == null -> PlaylistDetailError(
                message = uiState.playlistDetailError,
                onRetry = onRetry
            )
            uiState.playlistDetail != null -> {
                SectionTitle("Tracks")
                Spacer(modifier = Modifier.height(12.dp))
                if (tracks.isEmpty()) {
                    Text(
                        text = "No tracks yet",
                        style = MaterialTheme.typography.bodyMedium,
                        color = FurumiTextMuted
                    )
                } else {
                    tracks.forEachIndexed { index, track ->
                        PlaylistTrackRow(
                            index = index + 1,
                            track = track,
                            bitmap = mediaImageFor(uiState.mediaImages, track.coverUrl),
                            isLiked = uiState.likedTrackIds.contains(track.id),
                            onMediaImageNeeded = onMediaImageNeeded,
                            onTrackClick = onTrackClick,
                            onToggleLike = { onToggleLike(track.id) },
                            onPlayNext = { onPlayNext(track) },
                            onPlayLast = { onPlayLast(track) },
                            onShare = { onShare(track) },
                            onAddToPlaylist = { onAddToPlaylist(track) }
                        )
                        if (index < tracks.lastIndex) {
                            Spacer(modifier = Modifier.height(12.dp))
                        }
                    }
                }
            }
        }

        Spacer(modifier = Modifier.height(24.dp))
    }
}

@Composable
internal fun LibraryLoading() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(180.dp),
        contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator(
            color = FurumiNeonPink,
            strokeWidth = 2.dp
        )
    }
}

@Composable
internal fun LibraryError(
    message: String,
    onRetry: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = "Could not load playlists",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.height(6.dp))
            Text(
                text = message,
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
            Spacer(modifier = Modifier.height(14.dp))
            PillAction(
                label = "Retry",
                selected = true,
                onClick = onRetry
            )
        }
    }
}

@Composable
internal fun LibraryEmpty() {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Text(
            text = "No playlists yet",
            modifier = Modifier.padding(16.dp),
            style = MaterialTheme.typography.bodyMedium,
            color = FurumiTextMuted
        )
    }
}

@Composable
private fun LibraryArtistsError(
    message: String,
    onRetry: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = "Could not load artists",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.height(6.dp))
            Text(
                text = message,
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
            Spacer(modifier = Modifier.height(14.dp))
            PillAction(
                label = "Retry",
                selected = true,
                onClick = onRetry
            )
        }
    }
}

@Composable
private fun LibraryArtistsEmpty() {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = "No uploaded artists yet",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.height(6.dp))
            Text(
                text = "Artists from your uploads will appear here.",
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
        }
    }
}

@Composable
private fun LibraryArtistsFooter(
    uiState: PlayerUiState,
    onLoadMore: () -> Unit
) {
    when {
        uiState.isLibraryArtistsLoadingMore -> {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(72.dp),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator(
                    color = FurumiNeonPink,
                    strokeWidth = 2.dp,
                    modifier = Modifier.size(24.dp)
                )
            }
        }

        uiState.libraryArtistsError != null -> {
            Surface(
                modifier = Modifier.fillMaxWidth(),
                shape = RoundedCornerShape(10.dp),
                color = FurumiSurface,
                border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
            ) {
                Row(
                    modifier = Modifier.padding(12.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Text(
                        text = "Could not load more artists",
                        modifier = Modifier.weight(1f),
                        style = MaterialTheme.typography.bodyMedium,
                        color = FurumiTextMuted,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis
                    )
                    Text(
                        text = "Retry",
                        modifier = Modifier
                            .clip(RoundedCornerShape(8.dp))
                            .clickable(onClick = onLoadMore)
                            .padding(horizontal = 10.dp, vertical = 8.dp),
                        style = MaterialTheme.typography.labelLarge,
                        color = FurumiNeonPink
                    )
                }
            }
        }

        uiState.libraryArtistsHasMore -> {
            LaunchedEffect(uiState.libraryArtists.size, uiState.libraryArtistsPage) {
                onLoadMore()
            }

            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(72.dp),
                contentAlignment = Alignment.Center
            ) {
                CircularProgressIndicator(
                    color = FurumiNeonPink,
                    strokeWidth = 2.dp,
                    modifier = Modifier.size(24.dp)
                )
            }
        }

        else -> {
            Text(
                text = "${uiState.libraryArtists.size} artists loaded",
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 18.dp),
                style = MaterialTheme.typography.labelSmall,
                color = FurumiTextMuted
            )
        }
    }
}

private fun orderedLibraryPlaylists(playlists: List<PlaylistCard>): List<PlaylistCard> {
    val (likes, regular) = playlists.partition { playlist -> playlist.isLikesPlaylist() }
    return likes + regular
}

private fun PlaylistCard.isLikesPlaylist(): Boolean {
    return id == -1L || kind.equals("likes", ignoreCase = true)
}

private fun PlaylistCard.canDeleteFromDetail(): Boolean {
    return isOwn && !isLikesPlaylist()
}

private fun playlistArtworkColors(playlist: PlaylistCard): List<Color> {
    return if (playlist.isLikesPlaylist()) {
        listOf(FurumiNeonPink, FurumiHotOrange, FurumiBlack)
    } else {
        artistArtworkColors(playlist.id)
    }
}

@Composable
internal fun PlaylistDetailLoading() {
    Box(
        modifier = Modifier
            .fillMaxWidth()
            .height(180.dp),
        contentAlignment = Alignment.Center
    ) {
        CircularProgressIndicator(
            color = FurumiNeonPink,
            strokeWidth = 2.dp
        )
    }
}

@Composable
internal fun PlaylistDetailError(
    message: String,
    onRetry: () -> Unit
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
        shape = RoundedCornerShape(12.dp),
        color = FurumiSurface,
        border = androidx.compose.foundation.BorderStroke(1.dp, FurumiLine)
    ) {
        Column(modifier = Modifier.padding(16.dp)) {
            Text(
                text = "Could not load playlist",
                style = MaterialTheme.typography.titleMedium,
                color = MaterialTheme.colorScheme.onBackground
            )
            Spacer(modifier = Modifier.height(6.dp))
            Text(
                text = message,
                style = MaterialTheme.typography.bodyMedium,
                color = FurumiTextMuted
            )
            Spacer(modifier = Modifier.height(14.dp))
            PillAction(
                label = "Retry",
                selected = true,
                onClick = onRetry
            )
        }
    }
}

@Composable
internal fun GenreGrid() {
    val genres = listOf(
        "Synthwave" to listOf(FurumiNeonPink, FurumiNeonViolet),
        "Electronic" to listOf(FurumiElectricCyan, FurumiSurfaceHigh),
        "Indie" to listOf(FurumiHotOrange, FurumiNeonPink),
        "Focus" to listOf(FurumiNeonViolet, FurumiSurface)
    )

    Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
        genres.chunked(2).forEach { row ->
            Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
                row.forEach { genre ->
                    GenreTile(
                        title = genre.first,
                        colors = genre.second,
                        modifier = Modifier.weight(1f)
                    )
                }
            }
        }
    }
}

@Composable
internal fun GenreTile(
    title: String,
    colors: List<Color>,
    modifier: Modifier
) {
    Box(
        modifier = modifier
            .height(110.dp)
            .clip(RoundedCornerShape(8.dp))
            .background(Brush.linearGradient(colors))
            .border(1.dp, Color.White.copy(alpha = 0.12f), RoundedCornerShape(8.dp))
            .padding(14.dp)
    ) {
        Text(
            text = title,
            style = MaterialTheme.typography.titleMedium,
            color = Color.White
        )
    }
}
