package moe.lava.neon.ui.util

import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.navigation3.runtime.NavEntry
import androidx.navigation3.scene.Scene
import androidx.navigation3.scene.SceneStrategy
import androidx.navigation3.scene.SceneStrategyScope
import androidx.window.core.layout.WindowSizeClass

private val listWidth = 350.dp
private val extraWidth = 300.dp
//private val minChatWidth = 250.dp

class ThreePaneScene<T : Any>(
    override val key: Any,
    override val previousEntries: List<NavEntry<T>>,
    val listEntry: NavEntry<T>?,
    val detailEntry: NavEntry<T>,
    val extraEntry: NavEntry<T>?,
) : Scene<T> {
    override val entries: List<NavEntry<T>> = listOfNotNull(listEntry, detailEntry, extraEntry)
    override val content: @Composable (() -> Unit) = {
        Row(modifier = Modifier.fillMaxSize()) {
            if (listEntry != null) {
                Column(modifier = Modifier.width(listWidth)) {
                    listEntry.Content()
                }
            }
            Column(modifier = Modifier.weight(1f)) {
                AnimatedContent(
                    targetState = detailEntry,
                    contentKey = { entry -> entry.contentKey },
                    transitionSpec = {
                        slideInHorizontally(
                            initialOffsetX = { it }
                        ) togetherWith
                                slideOutHorizontally(targetOffsetX = { -it })
                    }
                ){ entry ->
                    entry.Content()
                }
            }
            if (extraEntry != null) {
                Column(modifier = Modifier.width(extraWidth)) {
                    AnimatedContent(
                        targetState = extraEntry,
                        contentKey = { entry -> entry.contentKey },
                        transitionSpec = {
                            slideInHorizontally(
                                initialOffsetX = { it }
                            ) togetherWith
                                    slideOutHorizontally(targetOffsetX = { -it })
                        }
                    ){ entry ->
                        entry.Content()
                    }
                }
            }
        }
    }
}

private const val LIST_KEY = "ThreePaneScene-List"
private const val DETAIL_KEY = "ThreePaneScene-Detail"
private const val EXTRA_KEY = "ThreePaneScene-Extra"

class ThreePaneSceneStrategy<T : Any>(val windowSizeClass: WindowSizeClass) : SceneStrategy<T> {
    override fun SceneStrategyScope<T>.calculateScene(entries: List<NavEntry<T>>): Scene<T>? {
        val useTwoPanes = when {
            windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_LARGE_LOWER_BOUND)
                -> false
            windowSizeClass.isWidthAtLeastBreakpoint(WindowSizeClass.WIDTH_DP_MEDIUM_LOWER_BOUND)
                -> true
            else -> return null
        }

        val listEntry = entries.findLast { it.metadata.containsKey(LIST_KEY) } ?: return null
        val detailEntry = entries.findLast { it.metadata.containsKey(DETAIL_KEY) } ?: return null
        val extraEntry = entries.findLast { it.metadata.containsKey(EXTRA_KEY) }

        val sceneKey = listEntry.contentKey

        return ThreePaneScene(
            key = sceneKey,
            previousEntries = entries.dropLast(1),
            listEntry = listEntry.takeIf { !(useTwoPanes && extraEntry != null) },
//            listEntry = listEntry,
            detailEntry = detailEntry,
            extraEntry = extraEntry,
//            extraEntry = extraEntry.takeIf { !useTwoPanes },
        )
    }

    companion object {
        fun listPane() = mapOf(LIST_KEY to true)
        fun detailPane() = mapOf(DETAIL_KEY to true)
        fun extraPane() = mapOf(EXTRA_KEY to true)
    }
}

@Composable
fun <T : Any> rememberThreePaneSceneStrategy(): ThreePaneSceneStrategy<T> {
    val windowSizeClass = currentWindowAdaptiveInfo(true).windowSizeClass

    return remember(windowSizeClass) {
        ThreePaneSceneStrategy(windowSizeClass)
    }
}
