package ch.dissem.yaep.ui.common

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedCard
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import ch.dissem.yaep.domain.Clue
import ch.dissem.yaep.domain.Grid
import ch.dissem.yaep.domain.HorizontalClue
import ch.dissem.yaep.domain.NeighbourClue
import ch.dissem.yaep.domain.OrderClue
import ch.dissem.yaep.domain.SameColumnClue
import ch.dissem.yaep.domain.TripletClue
import org.jetbrains.compose.resources.painterResource
import yaep.commonui.generated.resources.Res
import yaep.commonui.generated.resources.neighbour
import yaep.commonui.generated.resources.order

fun Modifier.forClue(clue: DisplayClue<out Clue>, padding: Dp = 8.dp): Modifier = this
    .alpha(if (clue.isActive) 1f else 0.2f)
    .padding(padding)
    .onEitherPointerAction { clue.isActive = !clue.isActive }

@Composable
fun HorizontalClue(
    modifier: Modifier = Modifier,
    spacing: Dp,
    clue: HorizontalClue,
    isClueViolated: Boolean
) {
    ClueCard(
        modifier = modifier,
        spacing = spacing,
        isClueViolated = isClueViolated
    ) {
        Row {
            when (clue) {
                is NeighbourClue<*, *> -> {
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.a)
                    Icon(
                        modifier = Modifier.aspectRatio(1f).weight(1f),
                        painter = painterResource(Res.drawable.neighbour),
                        contentDescription = null
                    )
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.b)
                }

                is OrderClue<*, *> -> {
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.left)
                    Icon(
                        modifier = Modifier.aspectRatio(1f).weight(1f),
                        painter = painterResource(Res.drawable.order),
                        contentDescription = null
                    )
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.right)
                }

                is TripletClue<*, *, *> -> {
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.a)
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.b)
                    DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.c)
                }
            }
        }
    }
}

@Composable
fun VerticalClue(
    modifier: Modifier = Modifier,
    spacing: Dp,
    clue: SameColumnClue<*, *>,
    isClueViolated: Boolean = false
) {
    ClueCard(
        modifier = modifier.aspectRatio(0.5f),
        spacing = spacing,
        isClueViolated = isClueViolated
    ) {
        Column {
            DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.a)
            DrawItem(modifier = Modifier.weight(1f), spacing = spacing, item = clue.b)
        }
    }
}

@Composable
fun ClueCard(
    modifier: Modifier = Modifier,
    spacing: Dp,
    isClueViolated: Boolean,
    content: @Composable () -> Unit
) {
    val colors = MaterialTheme.colorScheme
    OutlinedCard(
        modifier = if (isClueViolated) {
            modifier.shadow(
                8.dp,
                shape = CardDefaults.outlinedShape,
                ambientColor = colors.error,
                spotColor = colors.error
            )
        } else {
            modifier
        },
        shape = RoundedCornerShape(spacing),
        border = if (isClueViolated) {
            remember { BorderStroke(1.0.dp, colors.error) }
        } else {
            CardDefaults.outlinedCardBorder()
        }
    ) {
        content()
    }
}

class DisplayClue<C : Clue>(val clue: C) {
    var isActive: Boolean by mutableStateOf(true)

    var isViolated: Boolean by mutableStateOf(false)

    fun update(grid: Grid) {
        isViolated = !clue.isValid(grid)
        if (isViolated) {
            isActive = true
        }
    }
}
