package com.kawomi.githugandroid

import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

fun movePane(layout: PaneLayout, paneId: PaneId, delta: Int): PaneLayout {
    val currentIndex = layout.order.indexOf(paneId)
    if (currentIndex == -1) return layout
    val targetIndex = (currentIndex + delta).coerceIn(0, layout.order.lastIndex)
    if (currentIndex == targetIndex) return layout

    val updatedOrder = layout.order.toMutableList()
    updatedOrder.removeAt(currentIndex)
    updatedOrder.add(targetIndex, paneId)
    return layout.copy(order = updatedOrder)
}

fun resizePanes(
    layout: PaneLayout,
    upper: PaneId,
    lower: PaneId,
    dragFraction: Float,
): PaneLayout {
    if (upper in layout.collapsed || lower in layout.collapsed) return layout

    val minWeight = 0.6f
    val upperWeight = layout.weights[upper] ?: 1f
    val lowerWeight = layout.weights[lower] ?: 1f
    val scaledDelta = dragFraction.coerceIn(-0.75f, 0.75f)

    val newUpper = (upperWeight + scaledDelta).coerceAtLeast(minWeight)
    val newLower = (lowerWeight - scaledDelta).coerceAtLeast(minWeight)

    return layout.copy(
        weights = layout.weights + mapOf(
            upper to newUpper,
            lower to newLower,
        )
    )
}

fun recommendedPaneHeights(
    level: Level,
    levelCount: Int,
    outputLineCount: Int,
    screenHeightDp: Int,
    suggestionsVisible: Boolean,
    visibleHint: String?,
): Map<PaneId, Int> {
    val screenHeight = screenHeightDp.coerceAtLeast(560)
    val levelsHeight = (56 + levelCount * 44).coerceAtLeast(160)
    val descriptionLines = (level.description.length / 42).coerceAtLeast(2) + 2
    val suggestionsLines = if (suggestionsVisible) level.commandSuggestions.size + 1 else 0
    val hintLines = visibleHint?.let { (it.length / 42).coerceAtLeast(1) + 1 } ?: 0
    val exerciseHeight = (120 + descriptionLines * 24 + suggestionsLines * 22 + hintLines * 22).coerceAtLeast(180)
    val terminalHeight = (170 + outputLineCount.coerceAtLeast(1) * 20).coerceAtMost((screenHeight * 0.7f).toInt())
    val visualHeight = (screenHeight * 0.24f).toInt().coerceAtLeast(170)

    return mapOf(
        PaneId.EXERCISE to exerciseHeight,
        PaneId.TERMINAL to terminalHeight,
        PaneId.VISUAL to visualHeight,
        PaneId.LEVELS to levelsHeight,
    )
}

fun recommendedPaneWeights(
    heights: Map<PaneId, Int>,
): Map<PaneId, Float> {
    fun weightFor(height: Int): Float = (height / 180f).coerceAtLeast(0.6f)

    return heights.mapValues { (_, height) -> weightFor(height) }
}

fun recommendedWorkspaceHeight(
    paneLayout: PaneLayout,
    recommendedHeights: Map<PaneId, Int>,
): Dp {
    val dividerHeight = 18 * (paneLayout.order.size - 1)
    val collapsedPaneHeight = 44 * paneLayout.collapsed.size
    val expandedHeight = paneLayout.order
        .filterNot { it in paneLayout.collapsed }
        .sumOf { pane -> recommendedHeights[pane] ?: 0 }
    return (expandedHeight + dividerHeight + collapsedPaneHeight).dp
}

fun commonPrefix(values: List<String>): String {
    if (values.isEmpty()) return ""
    var prefix = values.first()
    values.drop(1).forEach { value ->
        while (!value.startsWith(prefix) && prefix.isNotEmpty()) {
            prefix = prefix.dropLast(1)
        }
    }
    return prefix
}