package com.anypreta.bountyboard.ui.nav

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
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.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
import androidx.compose.material.icons.outlined.DarkMode
import androidx.compose.material.icons.outlined.LightMode
import androidx.compose.material.icons.outlined.Logout
import androidx.compose.material.icons.outlined.Menu
import androidx.compose.material.icons.outlined.Notifications
import androidx.compose.material3.Badge
import androidx.compose.material3.BadgedBox
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalDrawerSheet
import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.DrawerValue
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
import com.anypreta.bountyboard.data.push.PushNotifier
import com.anypreta.bountyboard.di.LocalAppContainer
import com.anypreta.bountyboard.di.containerVMFactory
import com.anypreta.bountyboard.ui.admin.AdminAuditScreen
import com.anypreta.bountyboard.ui.admin.AdminCustomersScreen
import com.anypreta.bountyboard.ui.admin.AdminServiceStatusScreen
import com.anypreta.bountyboard.ui.admin.AdminSettingsScreen
import com.anypreta.bountyboard.ui.admin.AdminUsersScreen
import com.anypreta.bountyboard.ui.admin.CustomerEditScreen
import com.anypreta.bountyboard.ui.components.BBAvatar
import com.anypreta.bountyboard.ui.components.DiamondBrand
import com.anypreta.bountyboard.ui.components.Hairline
import com.anypreta.bountyboard.ui.consultant.ConsultantBoardScreen
import com.anypreta.bountyboard.ui.consultant.ConsultantMetricsScreen
import com.anypreta.bountyboard.ui.consultant.PoolScreen
import com.anypreta.bountyboard.ui.consultant.ReviewsScreen
import com.anypreta.bountyboard.ui.developer.BoardScreen
import com.anypreta.bountyboard.ui.developer.DeveloperMetricsScreen
import com.anypreta.bountyboard.ui.developer.LeaderboardScreen
import com.anypreta.bountyboard.ui.developer.MyTasksScreen
import com.anypreta.bountyboard.ui.messaging.ConversationScreen
import com.anypreta.bountyboard.ui.messaging.MessagesScreen
import com.anypreta.bountyboard.ui.profile.ProfileScreen
import com.anypreta.bountyboard.ui.profile.PublicProfileScreen
import com.anypreta.bountyboard.ui.shared.NotificationsScreen
import com.anypreta.bountyboard.ui.task.TaskDetailScreen
import com.anypreta.bountyboard.ui.theme.BB
import kotlinx.coroutines.launch

private val topLevelRoutes: Set<String> = setOf(
    Routes.BOARD, Routes.MY_TASKS, Routes.DEV_METRICS, Routes.LEADERBOARD,
    Routes.CONSULTANT_BOARD, Routes.REVIEWS, Routes.POOL, Routes.CONSULTANT_METRICS,
    Routes.ADMIN_USERS, Routes.ADMIN_CUSTOMERS, Routes.ADMIN_SETTINGS, Routes.ADMIN_AUDIT, Routes.ADMIN_STATUS,
    Routes.MESSAGES, Routes.NOTIFICATIONS, Routes.PROFILE,
)

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainShell() {
    val container = LocalAppContainer.current
    val shellVm: ShellViewModel = viewModel(factory = containerVMFactory(container) { ShellViewModel(it) })
    val user by container.session.user.collectAsStateWithLifecycle()
    val themeId by container.settings.theme.collectAsStateWithLifecycle(initialValue = "light")
    val unread by shellVm.unread.collectAsStateWithLifecycle()

    val navController = rememberNavController()
    val drawerState = rememberDrawerState(DrawerValue.Closed)
    val scope = rememberCoroutineScope()

    val backStack by navController.currentBackStackEntryAsState()
    val currentRoute = backStack?.destination?.route ?: Routes.BOARD
    val baseRoute = currentRoute.substringBefore("/")
    val isTopLevel = baseRoute in topLevelRoutes
    val sections = navSectionsFor(user)
    val p = BB.colors

    // Background delivery: the 15-min poll + the live-updates foreground service,
    // toggled together by the push preference.
    val pushEnabled by container.settings.pushEnabled.collectAsStateWithLifecycle(initialValue = true)
    LaunchedEffect(pushEnabled) {
        if (pushEnabled) {
            container.schedulePush()
            container.startLiveService()
        } else {
            container.cancelPush()
            container.stopLiveService()
        }
    }

    // Keep the WebSocket connected for the whole authenticated session; the service
    // raises system notifications when backgrounded — here we just keep the bell fresh.
    DisposableEffect(Unit) {
        container.live.connect()
        onDispose { /* kept alive across navigation; closed on logout */ }
    }
    LaunchedEffect(Unit) {
        container.live.notifications.collect { shellVm.refreshUnread() }
    }

    // Deep link from a tapped system notification.
    val deepLink by container.pendingDeepLink.collectAsStateWithLifecycle()
    LaunchedEffect(deepLink) {
        val target = deepLink ?: return@LaunchedEffect
        runCatching { navController.navigate(target) }
        container.consumeDeepLink()
    }

    fun navigateTop(route: String) {
        navController.navigate(route) {
            popUpTo(navController.graph.startDestinationId) { saveState = true }
            launchSingleTop = true
            restoreState = true
        }
    }

    ModalNavigationDrawer(
        drawerState = drawerState,
        gesturesEnabled = isTopLevel,
        drawerContent = {
            ModalDrawerSheet(
                drawerContainerColor = p.surface2,
                modifier = Modifier.width(280.dp),
            ) {
                DrawerContent(
                    sections = sections,
                    currentRoute = baseRoute,
                    onSelect = { route ->
                        scope.launch { drawerState.close() }
                        navigateTop(route)
                    },
                    onLogout = { shellVm.logout { container.cookieJar.clear() } },
                )
            }
        },
    ) {
        Scaffold(
            containerColor = p.bg,
            topBar = {
                TopAppBar(
                    title = {
                        if (isTopLevel) {
                            Text(
                                titleFor(baseRoute),
                                fontWeight = FontWeight.SemiBold,
                                color = p.text,
                                style = MaterialTheme.typography.titleLarge,
                            )
                        } else {
                            Text(
                                titleFor(baseRoute),
                                fontWeight = FontWeight.SemiBold,
                                color = p.text,
                                style = MaterialTheme.typography.titleMedium,
                            )
                        }
                    },
                    navigationIcon = {
                        if (isTopLevel) {
                            IconButton(onClick = { scope.launch { drawerState.open() } }) {
                                Icon(Icons.Outlined.Menu, "Menu", tint = p.text)
                            }
                        } else {
                            IconButton(onClick = { navController.popBackStack() }) {
                                Icon(Icons.AutoMirrored.Outlined.ArrowBack, "Back", tint = p.text)
                            }
                        }
                    },
                    actions = {
                        IconButton(onClick = { shellVm.toggleTheme() }) {
                            Icon(
                                if (themeId == "dark") Icons.Outlined.LightMode else Icons.Outlined.DarkMode,
                                "Toggle theme",
                                tint = p.text,
                            )
                        }
                        IconButton(onClick = { navController.navigate(Routes.NOTIFICATIONS) }) {
                            BadgedBox(badge = {
                                if (unread > 0) {
                                    Badge(containerColor = p.err, contentColor = Color.White) {
                                        Text(if (unread > 99) "99+" else unread.toString())
                                    }
                                }
                            }) {
                                Icon(Icons.Outlined.Notifications, "Notifications", tint = p.text)
                            }
                        }
                    },
                    colors = TopAppBarDefaults.topAppBarColors(
                        containerColor = p.surface2,
                        titleContentColor = p.text,
                    ),
                )
            },
        ) { padding ->
            Box(Modifier.padding(padding)) {
                MainNavHost(
                    navController = navController,
                    startDestination = homeRouteFor(user),
                    onUnreadChanged = { shellVm.refreshUnread() },
                )
            }
        }
    }
}

@Composable
private fun DrawerContent(
    sections: List<NavSection>,
    currentRoute: String,
    onSelect: (String) -> Unit,
    onLogout: () -> Unit,
) {
    val container = LocalAppContainer.current
    val user by container.session.user.collectAsStateWithLifecycle()
    val p = BB.colors
    Column(
        Modifier
            .fillMaxSize()
            .padding(horizontal = 16.dp)
            .verticalScroll(rememberScrollState()),
    ) {
        Spacer(Modifier.height(20.dp))
        DiamondBrand("Bounty Board")
        Spacer(Modifier.height(16.dp))
        Row(verticalAlignment = Alignment.CenterVertically) {
            BBAvatar(user?.name ?: "", user?.avatarFileId, size = 40.dp)
            Spacer(Modifier.width(10.dp))
            Column {
                Text(user?.name ?: "", style = MaterialTheme.typography.titleSmall, color = p.text, fontWeight = FontWeight.Bold)
                Text(user?.roleLabel() ?: "", style = MaterialTheme.typography.labelSmall, color = p.muted)
            }
        }
        Spacer(Modifier.height(16.dp))
        Hairline()
        Spacer(Modifier.height(12.dp))
        sections.forEach { section ->
            Text(
                section.title.uppercase(),
                style = MaterialTheme.typography.labelSmall,
                color = p.muted,
                modifier = Modifier.padding(vertical = 8.dp),
            )
            section.dests.forEach { dest ->
                DrawerItem(dest, selected = dest.route == currentRoute, onClick = { onSelect(dest.route) })
            }
            Spacer(Modifier.height(8.dp))
        }
        Hairline()
        Spacer(Modifier.height(8.dp))
        DrawerItemRaw(Icons.Outlined.Logout, "Log out", selected = false, onClick = onLogout)
        Spacer(Modifier.height(24.dp))
    }
}

@Composable
private fun DrawerItem(dest: NavDest, selected: Boolean, onClick: () -> Unit) {
    DrawerItemRaw(dest.icon, dest.label, selected, onClick)
}

@Composable
private fun DrawerItemRaw(
    icon: androidx.compose.ui.graphics.vector.ImageVector,
    label: String,
    selected: Boolean,
    onClick: () -> Unit,
) {
    val p = BB.colors
    val shape = RoundedCornerShape(p.radius.dp)
    Row(
        Modifier
            .fillMaxWidth()
            .clip(shape)
            .background(if (selected) p.surface else Color.Transparent)
            .then(if (selected) Modifier.padding(start = 0.dp) else Modifier)
            .clickableRow(onClick)
            .padding(horizontal = 12.dp, vertical = 11.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        if (selected) {
            Box(Modifier.width(3.dp).height(20.dp).background(p.accent))
            Spacer(Modifier.width(9.dp))
        } else {
            Spacer(Modifier.width(12.dp))
        }
        Icon(icon, null, tint = if (selected) p.accent else p.muted, modifier = Modifier.size(20.dp))
        Spacer(Modifier.width(12.dp))
        Text(
            label,
            style = MaterialTheme.typography.bodyMedium,
            color = if (selected) p.text else p.text.copy(alpha = 0.8f),
            fontWeight = if (selected) FontWeight.Bold else FontWeight.Normal,
        )
    }
}

private fun Modifier.clickableRow(onClick: () -> Unit): Modifier =
    this.clickable(onClick = onClick)

private fun titleFor(route: String): String = when (route) {
    Routes.BOARD -> "Bounty Board"
    Routes.MY_TASKS -> "My Tasks"
    Routes.DEV_METRICS, Routes.CONSULTANT_METRICS -> "Metrics"
    Routes.LEADERBOARD -> "Leaderboard"
    Routes.CONSULTANT_BOARD -> "Atomization Board"
    Routes.REVIEWS -> "Reviews"
    Routes.POOL -> "Developer Pool"
    Routes.ADMIN_USERS -> "Users"
    Routes.ADMIN_CUSTOMERS -> "Projects"
    Routes.ADMIN_SETTINGS -> "Settings"
    Routes.ADMIN_AUDIT -> "Audit Log"
    Routes.ADMIN_STATUS -> "Service Status"
    Routes.MESSAGES -> "Messages"
    Routes.NOTIFICATIONS -> "Notifications"
    Routes.PROFILE -> "Profile"
    Routes.TASK -> "Task"
    Routes.CONVERSATION -> "Conversation"
    Routes.CUSTOMER_EDIT -> "Project"
    Routes.PUBLIC_PROFILE -> "Profile"
    else -> "Bounty Board"
}

@Composable
private fun MainNavHost(
    navController: androidx.navigation.NavHostController,
    startDestination: String,
    onUnreadChanged: () -> Unit,
) {
    val openTask: (String) -> Unit = { id -> navController.navigate(Routes.task(id)) }
    val openProfile: (String) -> Unit = { id -> navController.navigate(Routes.publicProfile(id)) }
    val openConversation: (String) -> Unit = { id -> navController.navigate(Routes.conversation(id)) }

    NavHost(navController = navController, startDestination = startDestination) {
        // Developer
        composable(Routes.BOARD) { BoardScreen(onOpenTask = openTask) }
        composable(Routes.MY_TASKS) { MyTasksScreen(onOpenTask = openTask) }
        composable(Routes.DEV_METRICS) { DeveloperMetricsScreen() }
        composable(Routes.LEADERBOARD) { LeaderboardScreen(onOpenProfile = openProfile) }

        // Consultant
        composable(Routes.CONSULTANT_BOARD) { ConsultantBoardScreen(onOpenTask = openTask) }
        composable(Routes.REVIEWS) { ReviewsScreen(onOpenTask = openTask) }
        composable(Routes.POOL) { PoolScreen(onOpenProfile = openProfile) }
        composable(Routes.CONSULTANT_METRICS) { ConsultantMetricsScreen() }

        // Admin
        composable(Routes.ADMIN_USERS) { AdminUsersScreen(onOpenProfile = openProfile) }
        composable(Routes.ADMIN_CUSTOMERS) {
            AdminCustomersScreen(onEditCustomer = { id -> navController.navigate(Routes.customerEdit(id)) })
        }
        composable(
            "${Routes.CUSTOMER_EDIT}/{id}",
            arguments = listOf(navArgument("id") { type = NavType.StringType }),
        ) { entry ->
            CustomerEditScreen(
                customerId = entry.arguments?.getString("id") ?: "new",
                onDone = { navController.popBackStack() },
            )
        }
        composable(Routes.ADMIN_SETTINGS) { AdminSettingsScreen() }
        composable(Routes.ADMIN_AUDIT) { AdminAuditScreen() }
        composable(Routes.ADMIN_STATUS) { AdminServiceStatusScreen() }

        // Shared
        composable(Routes.MESSAGES) { MessagesScreen(onOpenConversation = openConversation) }
        composable(
            "${Routes.CONVERSATION}/{id}",
            arguments = listOf(navArgument("id") { type = NavType.StringType }),
        ) { entry ->
            ConversationScreen(conversationId = entry.arguments?.getString("id") ?: "", onOpenProfile = openProfile)
        }
        composable(Routes.NOTIFICATIONS) {
            NotificationsScreen(
                onOpenLink = { link -> handleNotificationLink(link, openTask, navController) },
                onChanged = onUnreadChanged,
            )
        }
        composable(Routes.PROFILE) { ProfileScreen() }
        composable(
            "${Routes.PUBLIC_PROFILE}/{id}",
            arguments = listOf(navArgument("id") { type = NavType.StringType }),
        ) { entry ->
            PublicProfileScreen(
                userId = entry.arguments?.getString("id") ?: "",
                onOpenConversation = openConversation,
            )
        }

        // Task detail
        composable(
            "${Routes.TASK}/{id}",
            arguments = listOf(navArgument("id") { type = NavType.StringType }),
        ) { entry ->
            TaskDetailScreen(
                taskId = entry.arguments?.getString("id") ?: "",
                onBack = { navController.popBackStack() },
                onOpenProfile = openProfile,
            )
        }
    }
}

private fun handleNotificationLink(
    link: String,
    openTask: (String) -> Unit,
    navController: androidx.navigation.NavHostController,
) {
    val clean = link.trim('/')
    when {
        clean.startsWith("tasks/") -> openTask(clean.removePrefix("tasks/"))
        clean == "board" -> navController.navigate(Routes.BOARD)
        clean.startsWith("conversations/") -> navController.navigate(Routes.conversation(clean.removePrefix("conversations/")))
        else -> {}
    }
}

@Suppress("unused")
private fun unusedPadding() = PaddingValues(0.dp)
