package com.fabledsword.minstrel.library.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.fabledsword.minstrel.cache.sync.SyncController
import com.fabledsword.minstrel.library.data.LibraryRepository
import com.fabledsword.minstrel.shared.UiState
import com.fabledsword.minstrel.shared.asCacheFirstStateFlow
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
import javax.inject.Inject

@HiltViewModel
class LibraryViewModel @Inject constructor(
    private val repository: LibraryRepository,
    private val syncController: SyncController,
    private val player: com.fabledsword.minstrel.player.PlayerController,
) : ViewModel() {

    val uiState: StateFlow<UiState<LibraryData>> =
        combine(
            repository.observeArtists(),
            repository.observeAlbums(),
            syncController.lastSyncError,
        ) { artists, albums, syncError ->
            when {
                artists.isNotEmpty() || albums.isNotEmpty() ->
                    UiState.Success(LibraryData(artists, albums))
                // Empty cache + failed sync is a load failure, not an empty
                // library — surface it so the user gets a Retry instead of
                // the welcome copy. Heals automatically: SyncController
                // re-syncs on health recovery, clearing lastSyncError.
                syncError != null -> UiState.Error(syncError)
                else -> UiState.Empty
            }
        }
            .asCacheFirstStateFlow(viewModelScope)

    /**
     * Pull-to-refresh entry point. Triggers /api/library/sync via the
     * SyncController; the resulting Room writes flow through the
     * observeArtists/observeAlbums flows to re-render the grids.
     */
    fun refresh(): Job = viewModelScope.launch {
        syncController.syncSafe()
    }

    /**
     * "Shuffle all" — fetches a random sample across the entire
     * library and starts playback. Silent on transport failure (user
     * can re-tap; the action has no inline error surface).
     */
    fun shuffleAll() {
        viewModelScope.launch {
            runCatching {
                val tracks = repository.shuffleLibrary()
                    .filter { it.streamUrl.isNotEmpty() }
                if (tracks.isNotEmpty()) {
                    player.setQueue(tracks, initialIndex = 0, source = "library_shuffle")
                }
            }
        }
    }
}
