package dev.privacyllc.period.navigation

import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CalendarMonth
import androidx.compose.material.icons.filled.Insights
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.filled.Today
import androidx.compose.material.icons.filled.Circle
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.compose.rememberNavController
import dev.privacyllc.period.R
import dev.privacyllc.period.designsystem.PeriodTheme
import dev.privacyllc.period.feature.calendar.CalendarScreen
import dev.privacyllc.period.feature.insights.InsightsScreen
import dev.privacyllc.period.feature.onboarding.OnboardingScreen
import dev.privacyllc.period.feature.settings.NotificationSettingsScreen
import dev.privacyllc.period.feature.settings.SettingsScreen
import dev.privacyllc.period.feature.today.TodayScreen

/**
 * The four tabs from docs/planning/PRODUCT_PLAN.md §20.
 *
 * Four and only four. Every proposal to add a fifth is answered by
 * docs/planning/PROJECT_PLAN.md's "deliberately not" list.
 */
enum class PeriodDestination(
    val route: String,
    @param:StringRes val labelRes: Int,
    val icon: ImageVector,
) {
    TODAY("today", R.string.tab_today, Icons.Filled.Today),
    CALENDAR("calendar", R.string.tab_calendar, Icons.Filled.CalendarMonth),
    INSIGHTS("insights", R.string.tab_insights, Icons.Filled.Insights),
    SETTINGS("settings", R.string.tab_settings, Icons.Filled.Settings),
}

/**
 * The root: onboarding, then the app.
 *
 * The decision comes from `UserPreferences.onboardingCompleted` and from
 * nowhere else. A second source — "does any period exist?" — would look
 * equivalent and is not: somebody who deletes all their data has not asked to be
 * onboarded again, and somebody who abandoned onboarding halfway has.
 */
@Composable
fun PeriodRoot(
    notificationAction: String? = null,
    viewModel: RootViewModel = hiltViewModel(),
) {
    val state by viewModel.state.collectAsStateWithLifecycle()

    // Applied once per delivered intent. Keyed on the action so a rotation does
    // not record a second "Not yet" the user never tapped.
    androidx.compose.runtime.LaunchedEffect(notificationAction) {
        viewModel.onNotificationAction(notificationAction)
    }

    when (state) {
        RootState.Loading -> Unit  // one frame; a spinner here flashes and reads as jank
        RootState.Onboarding -> OnboardingScreen(onFinished = viewModel::onboardingFinished)
        RootState.Ready -> PeriodApp()
    }
}

@Composable
fun PeriodApp() {
    val navController = rememberNavController()
    val backStackEntry by navController.currentBackStackEntryAsState()
    val currentDestination = backStackEntry?.destination

    Scaffold(
        bottomBar = {
            NavigationBar {
                PeriodDestination.entries.forEach { destination ->
                    val selected = currentDestination?.hierarchy?.any { it.route == destination.route } == true
                    NavigationBarItem(
                        selected = selected,
                        onClick = {
                            navController.navigate(destination.route) {
                                popUpTo(navController.graph.findStartDestination().id) { saveState = true }
                                launchSingleTop = true
                                restoreState = true
                            }
                        },
                        icon = { Icon(destination.icon, contentDescription = null) },
                        // maxLines and ellipsis, because at the largest
                        // accessibility font scale these labels do not fit and
                        // Compose's default is to wrap them mid-word: the tab
                        // bar reads "Calenda / r" and "Setting / s". Found by
                        // setting font_scale to 2.0 on a device, which nothing
                        // in the build does. Ellipsis degrades to "Calend…",
                        // which is still a word somebody can recognise, and the
                        // icon above it carries the meaning anyway.
                        label = {
                            Text(
                                stringResource(destination.labelRes),
                                maxLines = 1,
                                overflow = TextOverflow.Ellipsis,
                            )
                        },
                    )
                }
            }
        },
    ) { innerPadding ->
        NavHost(
            navController = navController,
            startDestination = PeriodDestination.TODAY.route,
            modifier = Modifier.padding(innerPadding),
        ) {
            composable(PeriodDestination.TODAY.route) { TodayScreen() }
            composable(PeriodDestination.CALENDAR.route) { CalendarScreen() }
            composable(PeriodDestination.INSIGHTS.route) { InsightsScreen() }

            // Settings is a root with children, so the tab lands on the §36
            // tree and reminders live one level down. The tab item's own
            // navigate() pops back to this start destination, which is what
            // makes tapping Settings from inside reminders return here rather
            // than doing nothing.
            composable(PeriodDestination.SETTINGS.route) {
                SettingsScreen(
                    onOpenNotifications = { navController.navigate(SETTINGS_NOTIFICATIONS) },
                )
            }
            composable(SETTINGS_NOTIFICATIONS) { NotificationSettingsScreen() }
        }
    }
}

/**
 * Skeleton only. Each of these is replaced by its real screen in Batch 03, and
 * saying "not built yet" on the screen is deliberate — a convincing mock is how
 * a screen comes to be believed finished.
 */
@Composable
private fun PlaceholderScreen(title: String) {
    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Icon(
            Icons.Filled.Circle,
            contentDescription = null,
            tint = MaterialTheme.colorScheme.primaryContainer,
        )
        Text(
            text = title,
            style = MaterialTheme.typography.headlineMedium,
            color = MaterialTheme.colorScheme.onBackground,
        )
        Text(
            text = "Not built yet",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant,
            textAlign = TextAlign.Center,
        )
    }
}

@Preview(showBackground = true)
@Composable
private fun PlaceholderPreview() {
    PeriodTheme { PlaceholderScreen("Calendar") }
}

/** Reminder settings, a child of the Settings tab rather than a fifth tab. */
private const val SETTINGS_NOTIFICATIONS = "settings/notifications"
