package dev.ulfrx.recipe.ui.components.recipe

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicText
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.composables.icons.lucide.Check
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.Plus
import com.composables.icons.lucide.Shuffle
import com.composables.icons.lucide.X
import com.composeunstyled.UnstyledButton
import com.composeunstyled.UnstyledIcon
import dev.ulfrx.recipe.ui.theme.RecipeTheme
import org.jetbrains.compose.resources.stringResource
import recipe.composeapp.generated.resources.Res
import recipe.composeapp.generated.resources.ingredient_substitute_a11y
import recipe.composeapp.generated.resources.meal_plan_editor_added_marker_a11y
import recipe.composeapp.generated.resources.meal_plan_editor_remove_ingredient_a11y

data class RecipeIngredientOptionUi(
    val id: String,
    val name: String,
    val amount: Double,
    val unit: String,
)

data class RecipeIngredientSlotUi(
    val default: RecipeIngredientOptionUi,
    val alternatives: List<RecipeIngredientOptionUi> = emptyList(),
    val id: String = default.id,
)

/**
 * Shared row used in both the read-only recipe detail and the meal-plan
 * editor. Detail uses the base form (name + optional swap + amount); editor
 * passes [onRemove] / [addedMarker] to surface its extra affordances inside
 * the same visual language.
 */
@Composable
fun IngredientRow(
    slot: RecipeIngredientSlotUi,
    modifier: Modifier = Modifier,
    selectedOptionId: String = slot.default.id,
    onSelect: ((RecipeIngredientOptionUi) -> Unit)? = null,
    addedMarker: Boolean = false,
    onRemove: (() -> Unit)? = null,
) {
    val options = slot.options
    val selected = options.firstOrNull { it.id == selectedOptionId } ?: slot.default
    val swappable = slot.alternatives.isNotEmpty() && onSelect != null
    var expanded by remember(slot.id) { mutableStateOf(false) }

    Column(
        modifier =
            modifier
                .fillMaxWidth()
                .animateContentSize(),
    ) {
        Row(
            modifier =
                Modifier
                    .fillMaxWidth()
                    .heightIn(min = MinRowHeight)
                    .padding(horizontal = PaddingHorizontal, vertical = PaddingVertical),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(RecipeTheme.spacing.sm),
        ) {
            NameLine(
                name = selected.name,
                addedMarker = addedMarker,
                modifier = Modifier.weight(1f),
            )
            if (swappable) {
                IconBadgeButton(
                    icon = Lucide.Shuffle,
                    contentDescription = stringResource(Res.string.ingredient_substitute_a11y),
                    onClick = { expanded = !expanded },
                )
            }
            IngredientAmount(amount = selected.amount, unit = selected.unit)
            if (onRemove != null) {
                IconBadgeButton(
                    icon = Lucide.X,
                    contentDescription = stringResource(Res.string.meal_plan_editor_remove_ingredient_a11y),
                    onClick = onRemove,
                )
            }
        }

        if (swappable && expanded) {
            Column(
                modifier =
                    Modifier
                        .fillMaxWidth()
                        .padding(start = PaddingHorizontal, end = PaddingHorizontal, bottom = PaddingVertical),
                verticalArrangement = Arrangement.spacedBy(RecipeTheme.spacing.sm),
            ) {
                options.forEach { option ->
                    AlternativeOption(
                        option = option,
                        selected = option.id == selected.id,
                        onClick = {
                            onSelect(option)
                            expanded = false
                        },
                    )
                }
            }
        }
    }
}

@Composable
private fun NameLine(
    name: String,
    addedMarker: Boolean,
    modifier: Modifier = Modifier,
) {
    val colors = RecipeTheme.colors
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.spacedBy(RecipeTheme.spacing.xs),
    ) {
        BasicText(
            text = name,
            style =
                RecipeTheme.typography.body.copy(
                    color = colors.content,
                    fontWeight = FontWeight.SemiBold,
                    fontSize = NameTextSize,
                    lineHeight = LineHeight,
                ),
        )
        if (addedMarker) {
            UnstyledIcon(
                imageVector = Lucide.Plus,
                contentDescription = stringResource(Res.string.meal_plan_editor_added_marker_a11y),
                tint = colors.contentMuted,
                modifier = Modifier.size(AddedMarkerSize),
            )
        }
    }
}

@Composable
private fun IconBadgeButton(
    icon: ImageVector,
    contentDescription: String,
    onClick: () -> Unit,
) {
    UnstyledButton(
        onClick = onClick,
        modifier = Modifier.size(ToggleSize),
    ) {
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            UnstyledIcon(
                imageVector = icon,
                contentDescription = contentDescription,
                tint = RecipeTheme.colors.contentMuted,
                modifier = Modifier.size(ToggleIconSize),
            )
        }
    }
}

@Composable
private fun AlternativeOption(
    option: RecipeIngredientOptionUi,
    selected: Boolean,
    onClick: () -> Unit,
) {
    val colors = RecipeTheme.colors
    val typography = RecipeTheme.typography
    UnstyledButton(
        onClick = onClick,
        backgroundColor = colors.background,
        contentColor = colors.content,
        shape = RoundedCornerShape(OptionCornerRadius),
        contentPadding = PaddingValues(OptionPadding),
        modifier = Modifier.fillMaxWidth(),
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(RecipeTheme.spacing.sm),
        ) {
            Column(modifier = Modifier.weight(1f)) {
                BasicText(
                    text = option.name,
                    style =
                        typography.body.copy(
                            color = colors.content,
                            fontWeight = FontWeight.Medium,
                            fontSize = OptionNameTextSize,
                            lineHeight = OptionNameLineHeight,
                        ),
                )
                Spacer(Modifier.height(OptionMetaGap))
                BasicText(
                    text = formatIngredientAmount(option.amount) + " " + option.unit,
                    style =
                        typography.body.copy(
                            color = colors.contentMuted,
                            fontSize = OptionMetaTextSize,
                            lineHeight = OptionMetaLineHeight,
                        ),
                )
            }
            SelectionMark(selected = selected)
        }
    }
}

@Composable
private fun SelectionMark(selected: Boolean) {
    val colors = RecipeTheme.colors
    Box(
        modifier =
            Modifier
                .size(SelectionMarkSize)
                .clip(RoundedCornerShape(percent = 50))
                .border(
                    width = SelectionMarkBorder,
                    color = colors.separator,
                    shape = RoundedCornerShape(percent = 50),
                ),
        contentAlignment = Alignment.Center,
    ) {
        if (selected) {
            UnstyledIcon(
                imageVector = Lucide.Check,
                contentDescription = null,
                tint = colors.contentMuted,
                modifier = Modifier.size(SelectionCheckSize),
            )
        }
    }
}

internal val RecipeIngredientSlotUi.options: List<RecipeIngredientOptionUi>
    get() = listOf(default) + alternatives

internal fun RecipeIngredientSlotUi.scaledBy(servings: Int) =
    RecipeIngredientSlotUi(
        default = default.copy(amount = default.amount * servings),
        alternatives = alternatives.map { it.copy(amount = it.amount * servings) },
        id = id,
    )

private val MinRowHeight = 48.dp
private val PaddingHorizontal = 12.dp
private val PaddingVertical = 12.dp
private val NameTextSize = 12.sp
private val LineHeight = 16.sp
private val ToggleSize = 24.dp
private val ToggleIconSize = 12.dp
private val AddedMarkerSize = 10.dp
private val OptionCornerRadius = 10.dp
private val OptionPadding = 12.dp
private val OptionMetaGap = 2.dp
private val OptionNameTextSize = 11.sp
private val OptionNameLineHeight = 14.sp
private val OptionMetaTextSize = 10.sp
private val OptionMetaLineHeight = 13.sp
private val SelectionMarkSize = 18.dp
private val SelectionMarkBorder = 1.5.dp
private val SelectionCheckSize = 10.dp
