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

import androidx.compose.ui.layout.Measurable
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.Constraints.Companion.fixedWidth

internal fun Placeable.PlacementScope.portrait(
    constraints: Constraints,
    spacingPx: Int,
    grid: FocusGroup,
    horizontalClues: FocusGroup,
    verticalClues: FocusGroup,
    timeMeasurable: Measurable,
    dividerMeasurables: List<Measurable>
) {
    val gridSize = constraints.maxWidth
    val gridItemSize = (gridSize - 12 * spacingPx) / 18

    val gridConstraints = fixed(gridSize, gridSize)
    val horizontalCluesConstraints = fixed(
        width = 3 * gridItemSize + 2 * spacingPx,
        height = gridItemSize + 2 * spacingPx
    )
    val verticalCluesConstraints = fixed(
        width = gridItemSize + 2 * spacingPx,
        height = 3 * gridItemSize + 2 * spacingPx
    )
    val timeConstraints = Constraints()
    val dividerConstraints = fixedWidth(gridSize)

    val gridPlaceable = grid.item.measure(gridConstraints)
    val gridBoxPlaceable = grid.box.measure(gridConstraints)
    val horizontalCluesPlaceables = horizontalClues.items.map {
        it.measure(horizontalCluesConstraints)
    }
    val verticalCluesPlaceables = verticalClues.items.map {
        it.measure(verticalCluesConstraints)
    }
    val timePlaceable = timeMeasurable.measure(timeConstraints)
    val divider1Placeable = dividerMeasurables[0].measure(dividerConstraints)
    val divider2Placeable = dividerMeasurables[1].measure(dividerConstraints)

    val horizontalCluesBoxPlaceable = horizontalClues.box
        .measure(
            cluesBoxConstraints(
                width = gridSize,
                itemConstraints = horizontalCluesConstraints,
                group = horizontalClues
            )
        )
    val verticalCluesBoxPlaceable = verticalClues.box
        .measure(
            cluesBoxConstraints(
                width = gridSize,
                itemConstraints = verticalCluesConstraints,
                group = verticalClues
            )
        )

    // Position the grid
    gridBoxPlaceable.place(0, 0)
    gridPlaceable.place(0, 0)

    divider1Placeable.place(0, gridSize + spacingPx)

    // Position the horizontal clues
    val horizontalCluesOffsetY = gridSize + 2 * spacingPx

    horizontalCluesBoxPlaceable.place(0, horizontalCluesOffsetY)
    var offsetY = placeClues(
        placeables = horizontalCluesPlaceables,
        offsetX = 0,
        offsetY = horizontalCluesOffsetY,
        maxWidth = gridSize
    )

    if (verticalClues.hasItems) {
        // Add divider in between
        divider2Placeable.place(0, offsetY + spacingPx)

        // Position the vertical clues
        val verticalCluesOffsetY = offsetY + spacingPx + divider2Placeable.height
        verticalCluesBoxPlaceable.place(0, verticalCluesOffsetY)
        offsetY = placeClues(
            placeables = verticalCluesPlaceables,
            offsetX = 0,
            offsetY = verticalCluesOffsetY,
            maxWidth = gridSize
        )
    }
    // Position the time
    val remainingSpace = constraints.maxHeight - offsetY
    if (remainingSpace < timePlaceable.height) {
        val scale = remainingSpace.toFloat() / timePlaceable.height.toFloat()
        if (scale > 0.1f) {
            timePlaceable.placeWithLayer(
                x = constraints.maxWidth - timePlaceable.width - spacingPx,
                y = constraints.maxHeight - timePlaceable.height
            ) {
                scaleX = scale
                scaleY = scale
                translationX = (timePlaceable.width * (1 - scale)) / 2f
                translationY = (timePlaceable.height * (1 - scale)) / 2f
            }
        }
    } else {
        timePlaceable.place(
            x = constraints.maxWidth - timePlaceable.width - spacingPx,
            y = constraints.maxHeight - timePlaceable.height
        )
    }
}
