package ch.dissem.yaep.ui.common

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.OutlinedCard
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.drawText
import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Item
import ch.dissem.yaep.domain.ItemClass
import ch.dissem.yaep.ui.common.theme.emojiFontFamily
import kotlin.math.min

@Composable
fun <C : ItemClass<C>> Selector(
    modifier: Modifier = Modifier,
    spacing: Dp = 4.dp,
    options: List<Toggleable<Item<C>>>,
    onOptionRemoved: (Item<C>) -> Unit,
    onOptionAdded: (Item<C>) -> Unit,
    selectedItem: Item<C>?,
    onSelectItem: (Item<C>?) -> Unit,
) {
    val radius = spacing * 1.5f
    if (selectedItem != null) {
        DrawItem(
            item = selectedItem,
            modifier = modifier.onEitherPointerAction { onSelectItem(null) },
            spacing = radius
        )
    } else {
        OutlinedCard(
            modifier = modifier.aspectRatio(1f),
            shape = RoundedCornerShape(radius)
        ) {
            LazyVerticalGrid(
                columns = GridCells.Fixed(3),
                verticalArrangement = Arrangement.Center,
                horizontalArrangement = Arrangement.Center
            ) {
                for (option in options) {
                    item {
                        DrawItem(
                            item = option.item,
                            modifier = Modifier
                                .alpha(if (option.enabled) 1f else 0.1f)
                                .onPointerAction(
                                    primary = { onSelectItem(option.item) },
                                    secondary = {
                                        if (option.enabled) {
                                            option.enabled = false
                                            onOptionRemoved(option.item)
                                        } else {
                                            option.enabled = true
                                            onOptionAdded(option.item)
                                        }
                                    }
                                ),
                            spacing = radius
                        )
                    }
                }
            }
        }
    }
}

@Composable
fun <C : ItemClass<C>> DrawItem(
    modifier: Modifier = Modifier,
    item: Item<C>,
    spacing: Dp = 4.dp
) {
    OutlinedCard(modifier = modifier.aspectRatio(1f), shape = RoundedCornerShape(spacing)) {
        val emoji = item.symbol

        val textMeasurer = rememberTextMeasurer()

        Canvas(
            modifier = Modifier.fillMaxSize(1f),
            onDraw = {
                val textSize = textMeasurer.measure(text = emoji)
                val minTextSizeDimension = min(
                    textSize.size.width,
                    textSize.size.height
                )
                val fontSizeBase = minTextSizeDimension * min(
                    size.width / textSize.size.width,
                    size.height / textSize.size.height
                )
                val fontSize = (0.9f * fontSizeBase).toDp().toSp()

                val offset = Offset(
                    x = size.width / 2 - textSize.size.width * fontSizeBase / (2f * minTextSizeDimension),
                    y = size.height / 2 - textSize.size.height * fontSizeBase / (2f * minTextSizeDimension)
                )
                drawText(
                    textMeasurer = textMeasurer,
                    text = emoji,
                    style = TextStyle(
                        fontSize = fontSize,
                        fontFamily = emojiFontFamily ?: TextStyle.Default.fontFamily
                    ),
                    topLeft = offset
                )
            }
        )
    }
}

class Toggleable<T>(val item: T, enabled: Boolean = true) {

    var enabled: Boolean by mutableStateOf(enabled)

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is Toggleable<*>) return false

        if (item != other.item) return false
        if (enabled != other.enabled) return false

        return true
    }

    override fun hashCode(): Int {
        var result = item.hashCode()
        result = 31 * result + enabled.hashCode()
        return result
    }
}
