package moe.lava.neon.ui

import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialExpressiveTheme
import androidx.compose.material3.MotionScheme
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
import androidx.navigation3.runtime.NavKey
import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
import androidx.navigation3.ui.NavDisplay
import androidx.savedstate.serialization.SavedStateConfiguration
import co.touchlab.kermit.Logger
import kotlinx.serialization.Serializable
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import moe.lava.neon.core.repository.AuthRepository
import moe.lava.neon.core.repository.CaptchaRepository
import moe.lava.neon.ui.screens.Login
import moe.lava.neon.ui.screens.Sample
import moe.lava.neon.ui.screens.chat.Chat
import moe.lava.neon.ui.screens.members.MembersList
import moe.lava.neon.ui.screens.navigator.Navigator
import moe.lava.neon.ui.screens.navigator.NavigatorModel
import moe.lava.neon.ui.screens.navigator.NavigatorPreviewProvider
import moe.lava.neon.ui.util.ThreePaneSceneStrategy
import moe.lava.neon.ui.util.rememberThreePaneSceneStrategy
import org.koin.compose.koinInject
import kotlin.system.exitProcess

object Route {
    @Serializable
    data object Login : NavKey

    @Serializable
    data object Sample : NavKey

    @Serializable
    data class Navigator(val left: Boolean) : NavKey

    @Serializable
    data object Chat : NavKey

    @Serializable
    data object MembersList : NavKey
}

private val config = SavedStateConfiguration {
    serializersModule = SerializersModule {
        polymorphic(NavKey::class) {
            subclass(Route.Login::class, Route.Login.serializer())
            subclass(Route.Sample::class, Route.Sample.serializer())
            subclass(Route.Navigator::class, Route.Navigator.serializer())
            subclass(Route.Chat::class, Route.Chat.serializer())
            subclass(Route.MembersList::class, Route.MembersList.serializer())
        }
    }
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun App() {
    Thread.setDefaultUncaughtExceptionHandler { t: Thread, e: Throwable ->
        Logger.withTag("neon.thrhandler").a("Uncaught from $t: ${e}\n${e.stackTraceToString()}", e)
        exitProcess(1)
    }

    val auth: AuthRepository = koinInject()
    val captcha: CaptchaRepository = koinInject()
    captcha.setHandler(getCaptchaHandler())

    MaterialExpressiveTheme(
        colorScheme = getColorScheme(),
        motionScheme = MotionScheme.expressive(),
    ) {
        val init = if (auth.loggedIn) Route.Sample else Route.Login
//        val backStack = rememberNavBackStack(config, init)
        val backStack = rememberNavBackStack(config, Route.Sample)
        val threePaneStrategy = rememberThreePaneSceneStrategy<NavKey>()
        NavDisplay(
            backStack = backStack,
            entryDecorators = listOf(
                rememberSaveableStateHolderNavEntryDecorator(),
                rememberViewModelStoreNavEntryDecorator(),
            ),
            onBack = { backStack.removeLastOrNull() },
            sceneStrategy = threePaneStrategy,
            entryProvider = entryProvider {
                entry<Route.Login> {
                    Login(
                        onSuccess = {
                            backStack.clear()
                            backStack.add(Route.Sample)
                        }
                    )
                }
                entry<Route.Sample> {
                    Sample(
                        navTest = {
                            backStack.add(Route.Navigator(it))
                            backStack.add(Route.Chat)
                            backStack.add(Route.MembersList)
                        },
                        onRequestLogout = {
                            backStack.clear()
                            backStack.add(Route.Login)
                        }
                    )
                }

                entry<Route.Navigator>(
                    metadata = ThreePaneSceneStrategy.listPane()
                ) { key ->
                    if (key.left) {
                        Navigator(
                            NavigatorPreviewProvider.base2.copy(
                                guildNavPosition = NavigatorModel.GuildNavPosition.LeftSidebar
                            )
                        )
                    } else {
                        Navigator(
                            NavigatorPreviewProvider.base2.copy(
                                guildNavPosition = NavigatorModel.GuildNavPosition.BottomSheet
                            )
                        )
                    }
                }

                entry<Route.Chat>(
                    metadata = ThreePaneSceneStrategy.detailPane()
                ) {
                    Chat(
                        onOpenMembers = { backStack.add(Route.MembersList) }
                    )
                }

                entry<Route.MembersList>(
                    metadata = ThreePaneSceneStrategy.extraPane()
                ) {
                    MembersList()
                }
            }
        )
    }
}
