package com.fabledsword.minstrel.likes.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
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.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import com.fabledsword.minstrel.api.ErrorCopy
import com.fabledsword.minstrel.connectivity.NetworkStatusController
import com.fabledsword.minstrel.connectivity.recoveries
import com.fabledsword.minstrel.likes.data.LikesRepository
import com.fabledsword.minstrel.library.widgets.AlbumCard
import com.fabledsword.minstrel.library.widgets.ArtistCard
import com.fabledsword.minstrel.models.AlbumRef
import com.fabledsword.minstrel.models.ArtistRef
import com.fabledsword.minstrel.models.TrackRef
import com.fabledsword.minstrel.nav.AlbumDetail
import com.fabledsword.minstrel.nav.ArtistDetail
import com.fabledsword.minstrel.player.PlayerController
import com.fabledsword.minstrel.shared.UiState
import com.fabledsword.minstrel.shared.asCacheFirstStateFlow
import com.fabledsword.minstrel.shared.widgets.TrackRow
import com.fabledsword.minstrel.shared.widgets.EmptyState
import com.fabledsword.minstrel.shared.widgets.ErrorRetry
import com.fabledsword.minstrel.shared.widgets.HorizontalScrollRow
import com.fabledsword.minstrel.shared.widgets.LikeButton
import com.fabledsword.minstrel.shared.widgets.LoadingCentered
import com.fabledsword.minstrel.shared.widgets.PullToRefreshScaffold
import com.fabledsword.minstrel.shared.widgets.TrackCoverThumb
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsButton
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import javax.inject.Inject

// ─── State ───────────────────────────────────────────────────────────

data class LikedSections(
    val artists: List<ArtistRef> = emptyList(),
    val albums: List<AlbumRef> = emptyList(),
    val tracks: List<TrackRef> = emptyList(),
) {
    val isAllEmpty: Boolean
        get() = artists.isEmpty() && albums.isEmpty() && tracks.isEmpty()
}

// ─── ViewModel ───────────────────────────────────────────────────────

@HiltViewModel
class LikedTabViewModel @Inject constructor(
    private val repository: LikesRepository,
    private val player: PlayerController,
    networkStatus: NetworkStatusController,
) : ViewModel() {

    /** Copy for the most recent refresh failure; null once one succeeds. */
    private val refreshError = MutableStateFlow<String?>(null)

    init {
        refresh()
        // Screen-level auto-recovery (issue #1245): re-pull when server
        // health returns, so a load that failed offline heals unprompted.
        viewModelScope.launch {
            networkStatus.recoveries().collect { refresh() }
        }
    }

    fun refresh(): Job = viewModelScope.launch {
        refreshError.value = null
        runCatching { repository.refreshIds() }
            .onFailure { refreshError.value = ErrorCopy.fromThrowable(it) }
    }

    /**
     * Unlike a track from inline heart-tap. The LikesRepository write
     * routes through the MutationQueue so offline taps replay later.
     */
    fun unlikeTrack(trackId: String) {
        viewModelScope.launch {
            repository.toggleLike(LikesRepository.ENTITY_TRACK, trackId, desiredState = false)
        }
    }

    val uiState: StateFlow<UiState<LikedSections>> = combine(
        repository.observeLikedArtists(),
        repository.observeLikedAlbums(),
        repository.observeLikedTracks(),
        refreshError,
    ) { artists, albums, tracks, err ->
        val sections = LikedSections(artists, albums, tracks)
        when {
            !sections.isAllEmpty -> UiState.Success(sections)
            // Empty cache + failed refresh is a load failure, not "no
            // likes yet" — surface Error so the user gets a Retry.
            err != null -> UiState.Error(err)
            else -> UiState.Empty
        }
    }.asCacheFirstStateFlow(viewModelScope)

    /**
     * Build a queue from the currently-displayed liked tracks and start
     * playback at [initialIndex]. Mirrors Flutter's tap-on-liked-track
     * behavior: the visible track list becomes the play queue. Tracks
     * with empty streamUrl are ignored as queue entries (the row that
     * routes here is itself click-gated on streamUrl).
     */
    fun playTracks(tracks: List<TrackRef>, initialIndex: Int) {
        if (tracks.isEmpty() || initialIndex !in tracks.indices) return
        if (tracks[initialIndex].streamUrl.isEmpty()) return
        player.setQueue(tracks, initialIndex = initialIndex, source = "liked")
    }
}

// ─── Composable ──────────────────────────────────────────────────────

@Composable
fun LikedTab(
    navController: NavHostController,
    viewModel: LikedTabViewModel = hiltViewModel(),
    playerViewModel: com.fabledsword.minstrel.player.ui.PlayerViewModel = hiltViewModel(),
) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    val playerState by playerViewModel.uiState.collectAsStateWithLifecycle()
    val playingTrackId = playerState.currentTrack?.id
    PullToRefreshScaffold(onRefresh = { viewModel.refresh().join() }) {
        when (val s = state) {
            UiState.Loading -> LoadingCentered()
            UiState.Empty -> EmptyState(
                title = "No likes yet",
                body = "Tap the heart on an artist, album, or track to start " +
                    "building your liked collection.",
            )
            is UiState.Error -> ErrorRetry(
                title = "Couldn't load likes",
                message = s.message,
                onRetry = { viewModel.refresh() },
            )
            is UiState.Success -> LikedContent(
                sections = s.data,
                playingTrackId = playingTrackId,
                onArtistClick = { id -> navController.navigate(ArtistDetail(id)) },
                onAlbumClick = { id -> navController.navigate(AlbumDetail(id)) },
                onTrackClick = { index ->
                    viewModel.playTracks(s.data.tracks, index)
                },
                onUnlike = viewModel::unlikeTrack,
                onNavigateToAlbum = { id -> navController.navigate(AlbumDetail(id)) },
                onNavigateToArtist = { id -> navController.navigate(ArtistDetail(id)) },
            )
        }
    }
}

@Composable
private fun LikedContent(
    sections: LikedSections,
    playingTrackId: String?,
    onArtistClick: (String) -> Unit,
    onAlbumClick: (String) -> Unit,
    onTrackClick: (Int) -> Unit,
    onUnlike: (String) -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        contentPadding = PaddingValues(vertical = 8.dp),
    ) {
        if (sections.artists.isNotEmpty()) {
            item {
                SectionHeader("Artists", sections.artists.size)
            }
            item {
                HorizontalScrollRow(title = "") {
                    items(items = sections.artists, key = { "art-${it.id}" }) { artist ->
                        ArtistCard(artist = artist, onClick = { onArtistClick(artist.id) })
                    }
                }
            }
        }
        if (sections.albums.isNotEmpty()) {
            item {
                SectionHeader("Albums", sections.albums.size)
            }
            item {
                HorizontalScrollRow(title = "") {
                    items(items = sections.albums, key = { "alb-${it.id}" }) { album ->
                        AlbumCard(album = album, onClick = { onAlbumClick(album.id) })
                    }
                }
            }
        }
        if (sections.tracks.isNotEmpty()) {
            item {
                SectionHeader("Tracks", sections.tracks.size)
            }
            itemsIndexed(items = sections.tracks, key = { _, t -> "trk-${t.id}" }) { index, track ->
                LikedTrackRow(
                    track = track,
                    nowPlaying = track.id == playingTrackId,
                    onClick = { onTrackClick(index) },
                    onUnlike = { onUnlike(track.id) },
                    onNavigateToAlbum = onNavigateToAlbum,
                    onNavigateToArtist = onNavigateToArtist,
                )
                HorizontalDivider()
            }
        }
        item { Spacer(Modifier.height(96.dp)) }
    }
}

@Composable
private fun SectionHeader(label: String, count: Int) {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp, vertical = 12.dp),
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(8.dp),
    ) {
        Text(
            text = label,
            style = MaterialTheme.typography.titleLarge,
            color = MaterialTheme.colorScheme.onBackground,
        )
        Text(
            text = "$count",
            style = MaterialTheme.typography.bodySmall,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
        )
    }
}

@Composable
private fun LikedTrackRow(
    track: TrackRef,
    nowPlaying: Boolean,
    onClick: () -> Unit,
    onUnlike: () -> Unit,
    onNavigateToAlbum: (String) -> Unit,
    onNavigateToArtist: (String) -> Unit,
) {
    TrackRow(
        title = track.title,
        artist = track.artistName.ifEmpty { track.albumTitle },
        trackId = track.id,
        onClick = onClick,
        nowPlaying = nowPlaying,
        enabled = track.streamUrl.isNotEmpty(),
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        leading = {
            TrackCoverThumb(coverUrl = track.coverUrl, contentDescription = track.title)
        },
        trailing = {
            LikeButton(liked = true, onToggle = onUnlike)
            TrackActionsButton(
                track = track,
                onNavigateToAlbum = onNavigateToAlbum,
                onNavigateToArtist = onNavigateToArtist,
            )
        },
    )
}
