package com.fabledsword.minstrel.shared.widgets

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import com.fabledsword.minstrel.cache.mutations.OfflineWriteHintViewModel
import com.fabledsword.minstrel.connectivity.ui.ConnectionErrorBanner
import com.fabledsword.minstrel.player.ui.MiniPlayer
import com.fabledsword.minstrel.player.ui.PlaybackErrorViewModel
import com.fabledsword.minstrel.update.ui.UpdateBanner
import com.fabledsword.minstrel.update.ui.VersionTooOldBanner
import com.fabledsword.minstrel.shared.widgets.trackactions.TrackActionsViewModel

/**
 * Outer shell wrapper for "in-app" routes — banners on top
 * (conditional, none implemented yet), routed screen filling the
 * middle, MiniPlayer pinned at the bottom (auto-hides when no track).
 * A shell-scoped SnackbarHost above the MiniPlayer surfaces transient
 * messages emitted by in-screen TrackActions kebabs (each screen owns
 * its own Scaffold's snackbar host as well; this one is the shell-
 * wide catch-all for events that outlive a single screen).
 *
 * Mirrors the Flutter `_ShellWithPlayerBar` (lib/shared/routing.dart).
 *
 * Top-level routes (Home / Library / Search / Discover / Playlists /
 * Settings / Admin / detail screens) wrap themselves with this.
 * Full-screen routes (NowPlaying / Queue / ServerUrl / Login)
 * intentionally do NOT — they fill the entire screen, often with a
 * back-only AppBar.
 *
 * [onExpandPlayer] is the navigate-to-NowPlaying callback passed
 * through to MiniPlayer's tap-handler. No NavHostController parameter
 * because nothing inside the shell currently navigates - if a banner
 * (UpdateBanner / VersionTooOldBanner / ConnectionErrorBanner) ever
 * grows tap-to-navigate, plumb a NavHostController in at that point.
 */
@Composable
fun ShellScaffold(
    onExpandPlayer: () -> Unit,
    modifier: Modifier = Modifier,
    trackActionsViewModel: TrackActionsViewModel = hiltViewModel(),
    playbackErrorViewModel: PlaybackErrorViewModel = hiltViewModel(),
    offlineWriteHintViewModel: OfflineWriteHintViewModel = hiltViewModel(),
    content: @Composable () -> Unit,
) {
    val snackbarHostState = remember { SnackbarHostState() }
    LaunchedEffect(Unit) {
        trackActionsViewModel.transientMessages.collect { msg ->
            snackbarHostState.showSnackbar(msg)
        }
    }
    LaunchedEffect(Unit) {
        playbackErrorViewModel.messages.collect { msg ->
            snackbarHostState.showSnackbar(msg)
        }
    }
    LaunchedEffect(Unit) {
        offlineWriteHintViewModel.messages.collect { msg ->
            snackbarHostState.showSnackbar(msg)
        }
    }
    // Consume the status-bar inset once here so the banner stack sits
    // below the status bar (mirrors Flutter's SafeArea(bottom:false)).
    // statusBarsPadding consumes the inset for descendants, so the in-
    // shell screens' app bars no longer re-pad for the status bar —
    // avoiding a double inset while fixing banners drawing under it.
    Column(modifier = modifier.fillMaxSize().statusBarsPadding()) {
        // Banner slot. VersionTooOldBanner appears when the server's
        // min_client_version exceeds our build; UpdateBanner softly
        // nudges an available (newer-than-installed) APK; and
        // ConnectionErrorBanner shows when the device loses usable
        // internet.
        VersionTooOldBanner()
        UpdateBanner()
        ConnectionErrorBanner()
        Box(modifier = Modifier.fillMaxWidth().weight(1f)) {
            content()
        }
        SnackbarHost(hostState = snackbarHostState)
        MiniPlayer(
            onExpandClick = onExpandPlayer,
        )
    }
}
