package com.fabledsword.minstrel.nav

import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import com.fabledsword.minstrel.admin.ui.AdminLandingScreen
import com.fabledsword.minstrel.admin.ui.AdminQuarantineScreen
import com.fabledsword.minstrel.admin.ui.AdminRequestsScreen
import com.fabledsword.minstrel.admin.ui.AdminTagSourcesScreen
import com.fabledsword.minstrel.admin.ui.AdminUsersScreen
import com.fabledsword.minstrel.auth.ui.LoginScreen
import com.fabledsword.minstrel.auth.ui.ServerUrlScreen
import com.fabledsword.minstrel.discover.ui.DiscoverScreen
import com.fabledsword.minstrel.home.ui.HomeScreen
import com.fabledsword.minstrel.library.ui.AlbumDetailScreen
import com.fabledsword.minstrel.library.ui.ArtistDetailScreen
import com.fabledsword.minstrel.library.ui.LibraryScreen
import com.fabledsword.minstrel.player.ui.NowPlayingScreen
import com.fabledsword.minstrel.player.ui.QueueScreen
import com.fabledsword.minstrel.playlists.ui.PlaylistDetailScreen
import com.fabledsword.minstrel.playlists.ui.PlaylistsListScreen
import com.fabledsword.minstrel.requests.ui.RequestsScreen
import com.fabledsword.minstrel.search.ui.SearchScreen
import com.fabledsword.minstrel.settings.ui.SettingsScreen
import com.fabledsword.minstrel.shared.widgets.ShellScaffold

/**
 * App NavHost. Mirrors the Flutter split between shell routes (wrapped
 * by `_ShellWithPlayerBar` → banners + screen + MiniPlayer) and
 * top-level non-shell routes (NowPlaying / Queue / unauthenticated).
 *
 * Per-route transition: only NowPlaying gets the modal slide-up; the
 * rest use the default fade.
 */
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable
fun MinstrelNavGraph(
    navController: NavHostController,
    startDestination: Any,
    modifier: Modifier = Modifier,
) {
    val expandPlayer = { navController.navigate(NowPlaying) }
    SharedTransitionLayout(modifier = modifier.fillMaxSize()) {
        CompositionLocalProvider(LocalSharedTransitionScope provides this) {
            NavHost(
                navController = navController,
                startDestination = startDestination,
                modifier = Modifier.fillMaxSize(),
            ) {
                inShellTopLevel(navController, expandPlayer)
                inShellDetail(navController, expandPlayer)
                outsideShell(navController)
            }
        }
    }
}

private fun NavGraphBuilder.inShellTopLevel(
    navController: NavHostController,
    expandPlayer: () -> Unit,
) {
    composable<Home> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                HomeScreen(navController = navController)
            }
        }
    }
    composable<Library> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                LibraryScreen(navController = navController)
            }
        }
    }
    composable<Search> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                SearchScreen(navController = navController)
            }
        }
    }
    composable<Discover> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                DiscoverScreen(navController = navController)
            }
        }
    }
    composable<Playlists> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                PlaylistsListScreen(navController = navController)
            }
        }
    }
    composable<Settings> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                SettingsScreen(navController = navController)
            }
        }
    }
    composable<Admin> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AdminLandingScreen(navController = navController)
            }
        }
    }
    composable<Requests> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                RequestsScreen(navController = navController)
            }
        }
    }
}

/**
 * Wraps content with [LocalAnimatedContentScope] sourced from the
 * enclosing `composable<>` lambda's [AnimatedContentScope] receiver
 * so the MiniPlayer / NowPlaying covers can apply
 * `Modifier.sharedElement(...)` for the Hero transition.
 *
 * Must be invoked from inside a `composable<>` lambda — its `this`
 * is the [AnimatedContentScope].
 */
@Composable
private fun AnimatedContentScope.WithAnimatedScope(
    content: @Composable () -> Unit,
) {
    CompositionLocalProvider(LocalAnimatedContentScope provides this) {
        content()
    }
}

private fun NavGraphBuilder.inShellDetail(
    navController: NavHostController,
    expandPlayer: () -> Unit,
) {
    composable<AlbumDetail> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AlbumDetailScreen(navController = navController)
            }
        }
    }
    composable<ArtistDetail> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                ArtistDetailScreen(navController = navController)
            }
        }
    }
    composable<PlaylistDetail> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                PlaylistDetailScreen(navController = navController)
            }
        }
    }
    composable<AdminRequests> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AdminRequestsScreen(navController = navController)
            }
        }
    }
    composable<AdminQuarantine> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AdminQuarantineScreen(navController = navController)
            }
        }
    }
    composable<AdminUsers> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AdminUsersScreen(navController = navController)
            }
        }
    }
    composable<AdminTagSources> {
        WithAnimatedScope {
            ShellScaffold(onExpandPlayer = expandPlayer) {
                AdminTagSourcesScreen(navController = navController)
            }
        }
    }
}

private fun NavGraphBuilder.outsideShell(navController: NavHostController) {
    composable<NowPlaying>(
        // Slide up from the bottom on enter; back down on dismiss.
        // Mirrors the Flutter CustomTransitionPage (280ms easeOutCubic).
        enterTransition = { slideInVertically(initialOffsetY = { it }) },
        exitTransition = { slideOutVertically(targetOffsetY = { it }) },
        popEnterTransition = { slideInVertically(initialOffsetY = { it }) },
        popExitTransition = { slideOutVertically(targetOffsetY = { it }) },
    ) {
        WithAnimatedScope {
            NowPlayingScreen(navController = navController)
        }
    }
    composable<Queue> { QueueScreen(navController = navController) }
    composable<ServerUrl> { ServerUrlScreen(navController = navController) }
    composable<Login> { LoginScreen(navController = navController) }
}

