@file:Suppress("TooManyFunctions") // Compose screen + private helper composables

package com.fabledsword.minstrel.library.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavHostController
import com.composables.icons.lucide.ArrowLeft
import com.composables.icons.lucide.Disc3
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Play
import com.composables.icons.lucide.Shuffle
import com.fabledsword.minstrel.models.AlbumDetailRef
import com.fabledsword.minstrel.models.AlbumRef
import com.fabledsword.minstrel.models.TrackRef
import com.fabledsword.minstrel.nav.AlbumDetail
import com.fabledsword.minstrel.nav.ArtistDetail
import com.fabledsword.minstrel.shared.formatDuration
import com.fabledsword.minstrel.shared.widgets.ShellContentWindowInsets
import com.fabledsword.minstrel.shared.widgets.TrackRow
import com.fabledsword.minstrel.shared.widgets.ErrorRetry
import com.fabledsword.minstrel.shared.widgets.LikeButton
import com.fabledsword.minstrel.shared.widgets.PullToRefreshScaffold
import com.fabledsword.minstrel.shared.widgets.ServerImage
import com.fabledsword.minstrel.shared.widgets.SkeletonTrackRow
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
import com.fabledsword.minstrel.theme.FabledSwordFlatTokens

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AlbumDetailScreen(
    navController: NavHostController,
    viewModel: AlbumDetailViewModel = hiltViewModel(),
    playerViewModel: com.fabledsword.minstrel.player.ui.PlayerViewModel = hiltViewModel(),
) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    Scaffold(
        contentWindowInsets = ShellContentWindowInsets,
        modifier = Modifier.fillMaxSize(),
        topBar = {
            TopAppBar(
                title = { Text(titleFor(state)) },
                navigationIcon = {
                    IconButton(onClick = { navController.popBackStack() }) {
                        Icon(Lucide.ArrowLeft, contentDescription = "Back")
                    }
                },
            )
        },
    ) { inner ->
        PullToRefreshScaffold(
            onRefresh = { viewModel.refresh().join() },
            modifier = Modifier.fillMaxSize().padding(inner),
        ) {
            AlbumDetailStateContent(
                state = state,
                viewModel = viewModel,
                playerViewModel = playerViewModel,
                navController = navController,
            )
        }
    }
}

private fun titleFor(state: AlbumDetailUiState): String = when (state) {
    is AlbumDetailUiState.Success -> state.detail.album.title
    is AlbumDetailUiState.Loading -> state.seed?.title ?: "Album"
    is AlbumDetailUiState.Error -> "Album"
}

@Composable
private fun AlbumDetailStateContent(
    state: AlbumDetailUiState,
    viewModel: AlbumDetailViewModel,
    playerViewModel: com.fabledsword.minstrel.player.ui.PlayerViewModel,
    navController: NavHostController,
) {
    // Crossfade keyed on `state::class` so a Success → fresh Success
    // refresh (same kind, new detail) doesn't re-fade the whole body;
    // only Loading ↔ Success ↔ Error transitions animate.
    Crossfade(targetState = state::class, label = "album-detail") { _ ->
        when (val s = state) {
            is AlbumDetailUiState.Loading ->
                if (s.seed != null) SeededAlbumLoading(s.seed) else SkeletonTrackList()
            is AlbumDetailUiState.Error -> ErrorRetry(
                title = "Couldn't load album",
                message = s.message,
                onRetry = { viewModel.refresh() },
            )
            is AlbumDetailUiState.Success -> {
                val albumLiked by viewModel.albumLiked.collectAsStateWithLifecycle()
                val likedTrackIds by viewModel.likedTrackIds
                    .collectAsStateWithLifecycle()
                val playerState by playerViewModel.uiState
                    .collectAsStateWithLifecycle()
                AlbumBody(
                    detail = s.detail,
                    albumLiked = albumLiked,
                    likedTrackIds = likedTrackIds,
                    playingTrackId = playerState.currentTrack?.id,
                    onPlayAll = { viewModel.play(startTrackId = null) },
                    onShuffleAll = viewModel::shuffle,
                    onTrackClick = { id -> viewModel.play(startTrackId = id) },
                    onToggleAlbumLike = viewModel::toggleLikeAlbum,
                    onToggleTrackLike = viewModel::toggleLikeTrack,
                    onNavigateToAlbum = { id ->
                        navController.navigate(AlbumDetail(id))
                    },
                    onNavigateToArtist = { id ->
                        navController.navigate(ArtistDetail(id))
                    },
                )
            }
        }
    }
}

@Composable
private fun AlbumBody(
    detail: AlbumDetailRef,
    albumLiked: Boolean,
    likedTrackIds: Set<String>,
    playingTrackId: String?,
    onPlayAll: () -> Unit,
    onShuffleAll: () -> Unit,
    onTrackClick: (String) -> Unit,
    onToggleAlbumLike: () -> Unit,
    onToggleTrackLike: (String) -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
    ) {
        item {
            AlbumHeader(
                album = detail.album,
                albumLiked = albumLiked,
                onPlayAll = onPlayAll,
                onShuffleAll = onShuffleAll,
                onToggleAlbumLike = onToggleAlbumLike,
            )
        }
        item { HorizontalDivider() }
        items(items = detail.tracks, key = { it.id }) { track ->
            TrackRow(
                track = track,
                liked = track.id in likedTrackIds,
                nowPlaying = track.id == playingTrackId,
                onClick = { onTrackClick(track.id) },
                onToggleLike = { onToggleTrackLike(track.id) },
                onNavigateToAlbum = onNavigateToAlbum,
                onNavigateToArtist = onNavigateToArtist,
            )
            HorizontalDivider()
        }
        if (detail.tracks.isEmpty()) {
            item {
                Text(
                    text = "No tracks on this album.",
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                    style = MaterialTheme.typography.bodyMedium,
                    modifier = Modifier.padding(24.dp),
                )
            }
        }
    }
}

@Composable
private fun AlbumHeader(
    album: AlbumRef,
    albumLiked: Boolean,
    onPlayAll: () -> Unit,
    onShuffleAll: () -> Unit,
    onToggleAlbumLike: () -> Unit,
) {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        Row(
            horizontalArrangement = Arrangement.spacedBy(16.dp),
            verticalAlignment = Alignment.CenterVertically,
        ) {
            AlbumCover(album)
            Column(modifier = Modifier.weight(1f)) {
                Text(
                    text = album.title,
                    style = MaterialTheme.typography.headlineSmall,
                    color = MaterialTheme.colorScheme.onBackground,
                    maxLines = 2,
                    overflow = TextOverflow.Ellipsis,
                )
                if (album.artistName.isNotEmpty()) {
                    Text(
                        text = album.artistName,
                        style = MaterialTheme.typography.bodyMedium,
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                        maxLines = 1,
                        overflow = TextOverflow.Ellipsis,
                    )
                }
                Spacer(Modifier.height(4.dp))
                Text(
                    text = trackCountLine(album),
                    style = MaterialTheme.typography.bodySmall,
                    color = MaterialTheme.colorScheme.onSurfaceVariant,
                )
            }
            LikeButton(liked = albumLiked, onToggle = onToggleAlbumLike)
        }
        Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
            Button(
                onClick = onPlayAll,
                colors = ButtonDefaults.buttonColors(),
            ) {
                Icon(Lucide.Play, contentDescription = null, modifier = Modifier.size(18.dp))
                Spacer(Modifier.width(8.dp))
                Text("Play")
            }
            OutlinedButton(onClick = onShuffleAll) {
                Icon(Lucide.Shuffle, contentDescription = null, modifier = Modifier.size(18.dp))
                Spacer(Modifier.width(8.dp))
                Text("Shuffle")
            }
        }
    }
}

@Composable
private fun AlbumCover(album: AlbumRef) {
    Box(
        modifier = Modifier
            .size(120.dp)
            .clip(RoundedCornerShape(FabledSwordFlatTokens.radiusSm))
            .background(MaterialTheme.colorScheme.surfaceVariant),
        contentAlignment = Alignment.Center,
    ) {
        if (album.id.isEmpty()) {
            Icon(
                imageVector = Lucide.Disc3,
                contentDescription = null,
                tint = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier.size(56.dp),
            )
        } else {
            ServerImage(
                url = album.displayCoverUrl,
                contentDescription = album.title,
                modifier = Modifier.fillMaxSize(),
            )
        }
    }
}

private fun trackCountLine(album: AlbumRef): String {
    val tracks = if (album.trackCount == 1) "1 track" else "${album.trackCount} tracks"
    return if (album.year != null) "$tracks · ${album.year}" else tracks
}

@Composable
private fun TrackRow(
    track: TrackRef,
    liked: Boolean,
    nowPlaying: Boolean,
    onClick: () -> Unit,
    onToggleLike: () -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    TrackRow(
        title = track.title,
        artist = track.artistName,
        trackId = track.id,
        onClick = onClick,
        nowPlaying = nowPlaying,
        leading = {
            Text(
                text = "${track.trackNumber ?: 0}",
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier.width(28.dp),
            )
        },
        trailing = {
            Text(
                text = formatDuration(track.durationSec, zero = "--:--"),
                style = MaterialTheme.typography.bodySmall,
                color = MaterialTheme.colorScheme.onSurfaceVariant,
                modifier = Modifier.padding(start = 12.dp),
            )
            LikeButton(liked = liked, onToggle = onToggleLike)
            TrackActionsButton(
                track = track,
                onNavigateToAlbum = onNavigateToAlbum,
                onNavigateToArtist = onNavigateToArtist,
            )
        },
    )
}

private const val SKELETON_TRACK_ROWS = 8

@Composable
private fun SkeletonTrackList() {
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        items(SKELETON_TRACK_ROWS) { SkeletonTrackRow() }
    }
}

/**
 * Loading body that renders the album header from the navigation seed
 * (cover + title + artist + count) so the screen reads as itself
 * immediately, with skeleton track rows below until the fetch lands.
 * Action buttons are omitted — they need the real track list.
 */
@Composable
private fun SeededAlbumLoading(seed: AlbumRef) {
    LazyColumn(modifier = Modifier.fillMaxSize()) {
        item {
            Row(
                modifier = Modifier.fillMaxWidth().padding(16.dp),
                horizontalArrangement = Arrangement.spacedBy(16.dp),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                AlbumCover(seed)
                Column(modifier = Modifier.weight(1f)) {
                    Text(
                        text = seed.title,
                        style = MaterialTheme.typography.headlineSmall,
                        color = MaterialTheme.colorScheme.onBackground,
                        maxLines = 2,
                        overflow = TextOverflow.Ellipsis,
                    )
                    if (seed.artistName.isNotEmpty()) {
                        Text(
                            text = seed.artistName,
                            style = MaterialTheme.typography.bodyMedium,
                            color = MaterialTheme.colorScheme.onSurfaceVariant,
                            maxLines = 1,
                            overflow = TextOverflow.Ellipsis,
                        )
                    }
                    Spacer(Modifier.height(4.dp))
                    Text(
                        text = trackCountLine(seed),
                        style = MaterialTheme.typography.bodySmall,
                        color = MaterialTheme.colorScheme.onSurfaceVariant,
                    )
                }
            }
        }
        item { HorizontalDivider() }
        items(SKELETON_TRACK_ROWS) { SkeletonTrackRow() }
    }
}
