package eu.gaudian.translator.view

import android.annotation.SuppressLint
import android.app.Activity
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDestination.Companion.hierarchy
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import dagger.hilt.android.AndroidEntryPoint
import eu.gaudian.translator.BuildConfig
import eu.gaudian.translator.MyApplication
import eu.gaudian.translator.R
import eu.gaudian.translator.ui.theme.AllFonts
import eu.gaudian.translator.ui.theme.AllThemes
import eu.gaudian.translator.ui.theme.ProvideSemanticColors
import eu.gaudian.translator.ui.theme.buildColorScheme
import eu.gaudian.translator.utils.Log
import eu.gaudian.translator.utils.StatusAction
import eu.gaudian.translator.utils.StatusMessageService
import eu.gaudian.translator.utils.findActivity
import eu.gaudian.translator.view.composable.AppAlertDialog
import eu.gaudian.translator.view.composable.BottomNavigationBar
import eu.gaudian.translator.view.composable.Screen
import eu.gaudian.translator.view.dialogs.WhatsNewDialog
import eu.gaudian.translator.view.hints.LocalShowHints
import eu.gaudian.translator.viewmodel.SettingsViewModel
import eu.gaudian.translator.viewmodel.StatusState
import eu.gaudian.translator.viewmodel.StatusViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.launch

val LocalShowExperimentalFeatures = compositionLocalOf { false }
val LocalConnectionConfigured = compositionLocalOf { true }

@AndroidEntryPoint
class MainActivity : ComponentActivity() {


    private val settingsViewModel: SettingsViewModel by viewModels()
    private var isReady = false
    private var isUiLoaded = false
    private var isInitializing = true

    override fun onCreate(savedInstanceState: Bundle?) {
        installSplashScreen().apply {
            // The splash screen will now correctly wait until isReady is true
            setKeepOnScreenCondition { !isReady }
        }

        super.onCreate(savedInstanceState)

        lifecycleScope.launch {
            settingsViewModel.theme.drop(1).collect { }
            settingsViewModel.fontPreference.drop(1).collect { }
        }

        WindowCompat.setDecorFitsSystemWindows(window, false)

        // Show UI immediately and load data in background
        setContent {
            AppTheme(settingsViewModel = settingsViewModel) {
                TranslatorApp(settingsViewModel = settingsViewModel)
            }
        }

        // Mark UI as loaded immediately after setContent
        isUiLoaded = true

        // Start initialization in background without blocking UI
        initializeData()
    }

    private fun initializeData() {
        lifecycleScope.launch(Dispatchers.IO) {
            // Get repositories from the Application instance (lazy initialization)
            val myApp = application as MyApplication
            val languageRepository = myApp.languageRepository
            val apiRepository = myApp.apiRepository

            // Perform initialization in parallel where possible
            val languageJob = launch {
                languageRepository.initializeDefaultLanguages()
                languageRepository.initializeAllLanguages()
            }

            val apiJob = launch {
                apiRepository.initialInit()
            }

            // Wait for both to complete
            languageJob.join()
            apiJob.join()

            // Signal readiness after all work is done.
            isReady = true
            isInitializing = false
        }
    }
}

@Suppress("AssignedValueIsNeverRead")
@SuppressLint("LocalContextResourcesRead")
@Composable
fun TranslatorApp(
    settingsViewModel: SettingsViewModel
) {

    val activity = LocalContext.current.findActivity()
    val statusViewModel: StatusViewModel = hiltViewModel(activity)
    val statusMessageService = StatusMessageService

    val navController = rememberNavController()
    val statusState by statusViewModel.status.collectAsStateWithLifecycle()
    val keyboardInsets = WindowInsets.ime
    val density = LocalDensity.current
    val isKeyboardVisible by remember {
        derivedStateOf {
            keyboardInsets.getBottom(density) > 0
        }
    }
    val introCompleted by settingsViewModel.introCompleted.collectAsStateWithLifecycle(initialValue = true)

    val showHints by settingsViewModel.showHints.collectAsStateWithLifecycle()
    val showExperimentalFeatures by settingsViewModel.experimentalFeatures.collectAsStateWithLifecycle()
    val connectionConfigured by settingsViewModel.connectionConfigured.collectAsStateWithLifecycle(initialValue = true)

    val isAtRoot = navController.previousBackStackEntry == null
    var showExitDialog by remember { mutableStateOf(false) }

    BackHandler(enabled = introCompleted && isAtRoot) {
        showExitDialog = true
    }


    if (showExitDialog) {
        AppAlertDialog(
            onDismissRequest = { showExitDialog = false },
            title = { Text(stringResource(R.string.label_quit_app)) },
            text = { Text(stringResource(R.string.text_do_you_want_to_minimize_the_app)) },
            confirmButton = {
                TextButton(onClick = {
                    showExitDialog = false
                    // Minimize the app similar to default back at root behavior
                    activity.moveTaskToBack(true)
                }) {
                    Text(stringResource(R.string.quit))
                }
            },
            dismissButton = {
                TextButton(onClick = { showExitDialog = false }) {
                    Text(stringResource(R.string.label_cancel))
                }
            }
        )
    }

    // Check for app updates and show "What's New" dialog if needed
    var showWhatsNewDialog by remember { mutableStateOf(false) }
    val context = LocalContext.current
    val changelogEntries = context.resources.getStringArray(R.array.changelog_entries)
    val latestChangelogEntry = changelogEntries.lastOrNull() ?: ""

    LaunchedEffect(Unit) {
        try {
            // Only check for updates if the intro is completed
            if (introCompleted) {
                val currentVersion = BuildConfig.VERSION_NAME
                val hasSeenCurrentVersion = settingsViewModel.hasSeenCurrentVersion(currentVersion)
                if (!hasSeenCurrentVersion) {
                    showWhatsNewDialog = true
                }
            }
        } catch (e: Exception) {
            @Suppress("HardCodedStringLiteral")
            Log.e("TranslatorApp", "Error checking version seen status", e)
        }
    }

    if (showWhatsNewDialog) {
        WhatsNewDialog(
            onDismissRequest = { showWhatsNewDialog = false },
            onContinue = {
                showWhatsNewDialog = false
                settingsViewModel.markVersionAsSeen(BuildConfig.VERSION_NAME)
            },
            changelogContent = latestChangelogEntry
        )
    }

    AppTheme(settingsViewModel = settingsViewModel) {
        CompositionLocalProvider(
            LocalShowHints provides showHints,
            LocalShowExperimentalFeatures provides showExperimentalFeatures,
            LocalConnectionConfigured provides connectionConfigured
        ) {
            if (introCompleted) {
                Box(modifier = Modifier.fillMaxSize()) {
                    Scaffold(
                        modifier = Modifier
                            .fillMaxSize()
                            .animateContentSize()
                            .imePadding(),
                        bottomBar = {
                            val navBackStackEntry by navController.currentBackStackEntryAsState()
                            val currentDestination = navBackStackEntry?.destination
                            val selectedScreen = Screen.fromDestination(currentDestination)

                            @Suppress("HardCodedStringLiteral") val isBottomBarHidden = currentDestination?.hierarchy?.any { destination ->
                                destination.route in setOf(
                                    Screen.Translation.route,
                                    Screen.Dictionary.route,
                                    Screen.Exercises.route,
                                    Screen.Settings.route
                                )
                            } == true || currentDestination?.route in setOf(
                                "start_exercise",
                                "new_word",
                                "new_word_review",
                                "vocabulary_detail/{itemId}"
                            )
                            val showBottomNavLabels by settingsViewModel.showBottomNavLabels.collectAsStateWithLifecycle(initialValue = false)

                            BottomNavigationBar(
                                selectedItem = selectedScreen,
                                isVisible = !isKeyboardVisible && !isBottomBarHidden,
                                showLabels = showBottomNavLabels,
                                onItemSelected = { screen ->
                                    val inSameSection = currentDestination?.hierarchy?.any { it.route == screen.route } == true
                                    val isMoreSection = screen in setOf(
                                        Screen.Translation,
                                        Screen.Dictionary,
                                        Screen.Settings,
                                        Screen.Exercises
                                    )

                                    // Always reset the selected section to its root and clear back stack between sections
                                    if (inSameSection) {
                                        // If already within the same section, ensure we are at its graph root
                                        navController.navigate(screen.route) {
                                            popUpTo(screen.route) {
                                                inclusive = false
                                                saveState = false
                                            }
                                            launchSingleTop = true
                                            restoreState = false
                                        }
                                    } else if (isMoreSection) {
                                        navController.navigate(screen.route) {
                                            launchSingleTop = true
                                            restoreState = false
                                        }
                                    } else {
                                        // Switching sections: clear entire back stack to start to avoid back navigation results
                                        navController.navigate(screen.route) {
                                            popUpTo(0) { // Pop everything
                                                inclusive = true
                                                saveState = false
                                            }
                                            launchSingleTop = true
                                            restoreState = false
                                        }
                                    }
                                },
                                onPlayClicked = {
                                    @Suppress("HardCodedStringLiteral")
                                    navController.navigate("start_exercise")
                                }
                            )
                        },
                        containerColor = MaterialTheme.colorScheme.background
                    ) { innerPadding ->
                        val animatedBottomPadding by androidx.compose.animation.core.animateDpAsState(
                            targetValue = innerPadding.calculateBottomPadding(),
                            label = "scaffoldBottomPad"
                        )
                        Column(
                            modifier = Modifier
                                .padding(
                                    start = innerPadding.calculateLeftPadding(androidx.compose.ui.unit.LayoutDirection.Ltr),
                                    top = innerPadding.calculateTopPadding(),
                                    end = innerPadding.calculateRightPadding(androidx.compose.ui.unit.LayoutDirection.Ltr),
                                    bottom = animatedBottomPadding
                                )
                                .fillMaxSize()
                        ) {
                            StatusMessageSystem(
                                statusState = statusState,
                                navController = navController,
                                onDismiss = { statusMessageService.trigger(StatusAction.HideMessageBar) },
                                modifier = Modifier
                                    .fillMaxWidth()
                            )
                            AppNavHost(
                                navController = navController,
                                modifier = Modifier.weight(1f)
                            )
                        }
                    }

                    if (statusState is StatusState.Loading) {
                        FullScreenLoadingOverlay()
                    }
                }
            } else {
                IntroNavHost(onIntroFinished = {
                    settingsViewModel.setIntroCompleted(true)
                })
            }
        }
    }
}

@Suppress("HardCodedStringLiteral")
@Composable
private fun AppTheme(
    settingsViewModel: SettingsViewModel,
    content: @Composable () -> Unit,
) {
    val themeName by settingsViewModel.theme.collectAsStateWithLifecycle()
    val darkModePref by settingsViewModel.darkModePreference.collectAsStateWithLifecycle()
    val fontName by settingsViewModel.fontPreference.collectAsStateWithLifecycle()

    val useDarkTheme = when (darkModePref) {
        "Light" -> false
        "Dark" -> true
        else -> isSystemInDarkTheme()
    }
    val context = LocalContext.current
    val colorScheme = if (themeName == "System" && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        if (useDarkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
    } else {
        val appTheme = AllThemes.find { it.name == themeName } ?: AllThemes.first()
        val colorSet = if (useDarkTheme) appTheme.darkColors else appTheme.lightColors
        buildColorScheme(colorSet, useDarkTheme)
    }

    val view = LocalView.current
    if (!view.isInEditMode) {
        SideEffect {
            val window = (view.context as Activity).window
            val windowInsetsController = WindowInsetsControllerCompat(window, view)

            // We must keep this for older Android version!!!
            @Suppress("DEPRECATION")
            window.statusBarColor = colorScheme.surface.toArgb()
            //Elevation must be the same as BottomNavigationBar
            @Suppress("DEPRECATION")
            window.navigationBarColor = colorScheme.surfaceColorAtElevation(8.dp).toArgb()

            windowInsetsController.isAppearanceLightStatusBars = !useDarkTheme
            windowInsetsController.isAppearanceLightNavigationBars = !useDarkTheme
        }
    }

    val selectedFontStyle = AllFonts.find { it.name == fontName } ?: AllFonts.first()

    val fontFamily = when (selectedFontStyle.fileName) {
        "default" -> FontFamily.Default
        "merriweather_regular" -> FontFamily(Font(R.font.merriweather_regular))
        "lato_regular" -> FontFamily(Font(R.font.lato_regular))
        "playfairdisplay_regular" -> FontFamily(Font(R.font.playfairdisplay_regular))
        "roboto_regular" -> FontFamily(Font(R.font.roboto_regular))
        "lora_regular" -> FontFamily(Font(R.font.lora_regular))
        "opensans_regular" -> FontFamily(Font(R.font.opensans_regular))
        else -> {
            Log.d("AppTheme", "Font not found: ${selectedFontStyle.name}")
            FontFamily.Default
        }
    }

    val dynamicTypography = androidx.compose.material3.Typography(
        bodyLarge = MaterialTheme.typography.bodyLarge.copy(fontFamily = fontFamily),
        bodyMedium = MaterialTheme.typography.bodyMedium.copy(fontFamily = fontFamily),
        bodySmall = MaterialTheme.typography.bodySmall.copy(fontFamily = fontFamily),
        headlineLarge = MaterialTheme.typography.headlineLarge.copy(fontFamily = fontFamily),
        headlineMedium = MaterialTheme.typography.headlineMedium.copy(fontFamily = fontFamily),
        headlineSmall = MaterialTheme.typography.headlineSmall.copy(fontFamily = fontFamily),
        titleLarge = MaterialTheme.typography.titleLarge.copy(fontFamily = fontFamily),
        titleMedium = MaterialTheme.typography.titleMedium.copy(fontFamily = fontFamily),
        titleSmall = MaterialTheme.typography.titleSmall.copy(fontFamily = fontFamily),
        labelLarge = MaterialTheme.typography.labelLarge.copy(fontFamily = fontFamily),
        labelMedium = MaterialTheme.typography.labelMedium.copy(fontFamily = fontFamily),
        labelSmall = MaterialTheme.typography.labelSmall.copy(fontFamily = fontFamily)
    )
    MaterialTheme(
        colorScheme = colorScheme,
        typography = dynamicTypography,
    ) {
        ProvideSemanticColors {
            content()
        }
    }


}