package com.pixelized.biblib.ui.screen.home.header

import androidx.compose.foundation.layout.Box
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.layoutId

@Composable
fun LazyGridCollapsingHeaderLayout(
    modifier: Modifier = Modifier,
    header: @Composable () -> Unit,
    lazyGrid: @Composable () -> Unit,
) {
    val headerHeight = rememberSaveable { mutableStateOf(0) }
    val headerScroll = rememberSaveable { mutableStateOf(0) }

    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                val scroll = (headerScroll.value + available.y.toInt()).coerceIn(
                    minimumValue = -headerHeight.value,
                    maximumValue = 0,
                )
                return if (headerScroll.value != scroll) {
                    headerScroll.value = scroll
                    available
                } else {
                    Offset.Zero
                }
            }
        }
    }

    Surface(
        color = MaterialTheme.colors.background,
    ) {
        Layout(
            modifier = modifier.nestedScroll(nestedScrollConnection),
            content = {
                Box(
                    modifier = Modifier.layoutId(HEADER_ID),
                    content = { header() },
                )
                Box(
                    modifier = Modifier.layoutId(GRID_ID),
                    content = { lazyGrid() },
                )
            },
            measurePolicy = { measurables, constraints ->
                val headerPlaceable = measurables.header.measure(constraints)
                val gridPlaceable = measurables.grid.measure(constraints)

                if (headerHeight.value == 0) {
                    headerHeight.value = headerPlaceable.height
                }

                layout(constraints.maxWidth, constraints.maxHeight) {
                    headerPlaceable.place(0, headerScroll.value)
                    gridPlaceable.place(0, headerPlaceable.height + headerScroll.value)
                }
            }
        )
    }
}

private val List<Measurable>.grid: Measurable get() = first { it.layoutId == GRID_ID }
private val List<Measurable>.header: Measurable get() = first { it.layoutId == HEADER_ID }

private const val GRID_ID = "GRID_ID"
private const val HEADER_ID = "HEADER_ID"