package ch.dissem.yaep.ui.common.layout

import androidx.compose.material3.HorizontalDivider
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Constraints.Companion.fixed
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.ui.common.focus.CluesSelectionManager
import ch.dissem.yaep.ui.common.focus.FocusFollowingFocusable
import ch.dissem.yaep.ui.common.focus.GridSelectionManager
import ch.dissem.yaep.ui.common.focus.SelectionManager
import ch.dissem.yaep.ui.common.layout.AspectRatio.LANDSCAPE
import ch.dissem.yaep.ui.common.layout.AspectRatio.PORTRAIT
import ch.dissem.yaep.ui.common.layout.AspectRatio.SQUARISH
import kotlin.math.ceil
import kotlin.math.max


@Composable
fun AdaptiveGameLayout(
    modifier: Modifier = Modifier,
    selectionManager: SelectionManager<FocusFollowingFocusable>,
    grid: @Composable (GridSelectionManager) -> Unit,
    horizontalClues: @Composable (SelectionManager<*>) -> Unit,
    verticalClues: @Composable (SelectionManager<*>) -> Unit,
    time: @Composable () -> Unit,
    vararg resetBeacons: Any
) {
    val gridFocusable = remember(*resetBeacons) { selectionManager.add() }
    val gridSelectionManager = remember(*resetBeacons) {  gridFocusable.create(GridSelectionManager()) }

    val horizontalCluesFocusable = remember(*resetBeacons) { selectionManager.add() }
    val horizontalCluesSelectionManager = remember(*resetBeacons) {
        horizontalCluesFocusable.create(CluesSelectionManager())
    }

    val verticalCluesFocusable = remember(*resetBeacons) { selectionManager.add() }
    val verticalCluesSelectionManager = remember(*resetBeacons) {
        verticalCluesFocusable.create(CluesSelectionManager())
    }
    Layout(
        contents = listOf(
            { grid(gridSelectionManager) },
            { FocusBox(gridFocusable, requestFocus = true) },
            { horizontalClues(horizontalCluesSelectionManager) },
            { FocusBox(horizontalCluesFocusable) },
            { verticalClues(verticalCluesSelectionManager) },
            { FocusBox(verticalCluesFocusable) },
            time,
            {
                HorizontalDivider()
                HorizontalDivider()
            }
        ),
        modifier = modifier
    ) { measurables, constraints ->
        layout(width = constraints.maxWidth, height = constraints.maxHeight) {
            val aspectRatio = AspectRatio.from(constraints)

            val gridGroup = FocusGroup(
                items = measurables[0],
                box = measurables[1][0],
            )
            val horizontalCluesGroup = FocusGroup(
                items = measurables[2],
                box = measurables[3][0],
                selectionManger = horizontalCluesSelectionManager
            )
            val verticalCluesGroup = FocusGroup(
                items = measurables[4],
                box = measurables[5][0],
                selectionManger = verticalCluesSelectionManager
            )
            val timeMeasurable = measurables[6][0]
            val dividerMeasurables = measurables[7]

            val spacingPx = 8.dp.roundToPx()

            when (aspectRatio) {
                PORTRAIT -> {
                    portrait(
                        constraints,
                        spacingPx,
                        gridGroup,
                        horizontalCluesGroup,
                        verticalCluesGroup,
                        timeMeasurable,
                        dividerMeasurables
                    )
                }

                SQUARISH -> {
                    squarish(
                        constraints,
                        spacingPx,
                        gridGroup,
                        horizontalCluesGroup,
                        verticalCluesGroup,
                        timeMeasurable
                    )
                }

                LANDSCAPE -> {
                    landscape(
                        constraints,
                        spacingPx,
                        gridGroup,
                        horizontalCluesGroup,
                        verticalCluesGroup,
                        timeMeasurable,
                        dividerMeasurables[0]
                    )
                }
            }
        }
    }
}

internal fun cluesBoxConstraints(
    width: Int,
    itemConstraints: Constraints,
    group: FocusGroup
): Constraints {
    val columns = width / itemConstraints.maxWidth
    group.selectionManger?.columns = columns
    return fixed(
        width,
        itemConstraints.maxHeight * ceil(group.count.toFloat() / columns).toInt()
    )
}

internal fun Placeable.PlacementScope.placeClues(
    placeables: List<Placeable>,
    offsetX: Int,
    offsetY: Int,
    maxWidth: Int
): Int {
    if (placeables.isEmpty()) return offsetY

    val itemWidth = placeables.first().width
    val itemHeight = placeables.first().height
    val columns = max(1, maxWidth / itemWidth)
    val spacing = if (columns == 1) 0 else (maxWidth - columns * itemWidth) / (columns - 1)
    var currentX = offsetX
    var currentY = offsetY
    var i = 0
    for (placeable in placeables) {
        placeable.place(currentX, currentY)
        currentX += itemWidth + spacing
        i++
        if (i % columns == 0 && i < placeables.size) {
            currentX = offsetX
            currentY += itemHeight
        }
    }
    return currentY + itemHeight
}

