package com.craigvg.lichun_android.ui.screens.dating import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.spring import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import com.craigvg.lichun_android.domain.models.EventChoice import com.craigvg.lichun_android.domain.models.RelationshipEvent import com.craigvg.lichun_android.domain.models.RelationshipEventType import com.craigvg.lichun_android.ui.theme.AppColors import com.craigvg.lichun_android.ui.theme.AppSpacing import com.craigvg.lichun_android.ui.theme.AppTypography import com.craigvg.lichun_android.viewmodel.PlayerViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.launch import androidx.lifecycle.compose.collectAsStateWithLifecycle /** * Relationship event modal for handling special relationship moments * Ported from iOS RelationshipEventModal.swift */ @Composable fun RelationshipEventModal( event: RelationshipEvent, playerViewModel: PlayerViewModel = hiltViewModel(), onDismiss: () -> Unit = {}, onChoiceSelected: (EventChoice) -> Unit = {} ) { val person by playerViewModel.person.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() var selectedChoice by remember { mutableStateOf(null) } var isProcessing by remember { mutableStateOf(false) } val eventTypeConfig = getEventTypeConfig(event.type) Box( modifier = Modifier .fillMaxSize() .background(AppColors.modalOverlay) .clickable(enabled = !isProcessing) { onDismiss() }, contentAlignment = Alignment.Center ) { // Modal Content Card( modifier = Modifier .fillMaxWidth(0.9f) .clickable(enabled = false) { /* Prevent dismiss when clicking on card */ }, shape = RoundedCornerShape(AppSpacing.largeCornerRadius), colors = CardDefaults.cardColors(containerColor = Color.Transparent), elevation = CardDefaults.cardElevation(defaultElevation = 8.dp) ) { Column( modifier = Modifier .background( Brush.verticalGradient( colors = listOf( AppColors.surfaceElevated, AppColors.background ) ) ) ) { // Header with event type HeaderSection( event = event, config = eventTypeConfig ) // Event description DescriptionSection(description = event.description) // Divider Box( modifier = Modifier .fillMaxWidth() .height(1.dp) .padding(horizontal = AppSpacing.md) .background( Brush.horizontalGradient( colors = listOf( Color.Transparent, AppColors.secondaryText.copy(alpha = 0.2f), Color.Transparent ) ) ) ) // Choices Column( modifier = Modifier .fillMaxWidth() .verticalScroll(rememberScrollState()) .padding(AppSpacing.md), verticalArrangement = Arrangement.spacedBy(AppSpacing.sm) ) { event.choices.forEach { choice -> val canAfford = choice.canAfford( energy = person.calcEnergy, money = person.money, diamonds = person.diamonds ) ChoiceCard( choice = choice, isSelected = selectedChoice?.id == choice.id, canAfford = canAfford, isProcessing = isProcessing, eventTypeConfig = eventTypeConfig, onClick = { if (canAfford && !isProcessing) { selectedChoice = choice isProcessing = true scope.launch { delay(500) onChoiceSelected(choice) onDismiss() } } } ) } } } } } } @Composable private fun HeaderSection( event: RelationshipEvent, config: EventTypeConfig ) { Column( modifier = Modifier .fillMaxWidth() .padding(AppSpacing.md), horizontalAlignment = Alignment.CenterHorizontally ) { // Decorative top accent Row( horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs) ) { repeat(5) { Box( modifier = Modifier .size(6.dp) .clip(CircleShape) .background( Brush.horizontalGradient( colors = listOf( AppColors.primary.copy(alpha = 0.4f), AppColors.secondary.copy(alpha = 0.4f) ) ) ) ) } } Spacer(modifier = Modifier.height(AppSpacing.sm)) // Icon with gradient background Box( modifier = Modifier.size(80.dp), contentAlignment = Alignment.Center ) { // Outer glow Box( modifier = Modifier .size(80.dp) .clip(CircleShape) .background( Brush.radialGradient( colors = listOf( config.backgroundColor.copy(alpha = 0.8f), config.backgroundColor.copy(alpha = 0.3f), Color.Transparent ) ) ) ) // Main circle Box( modifier = Modifier .size(64.dp) .clip(CircleShape) .background( Brush.linearGradient( colors = listOf( config.backgroundColor, config.backgroundColor.copy(alpha = 0.7f) ) ) ), contentAlignment = Alignment.Center ) { Icon( imageVector = config.icon, contentDescription = null, tint = config.iconColor, modifier = Modifier.size(30.dp) ) } } Spacer(modifier = Modifier.height(AppSpacing.xs)) // Title Text( text = event.title, style = AppTypography.largeTitle, color = AppColors.primaryText, textAlign = TextAlign.Center ) // Decorative line Box( modifier = Modifier .width(120.dp) .height(2.dp) .background( Brush.horizontalGradient( colors = listOf( Color.Transparent, config.iconColor.copy(alpha = 0.4f), Color.Transparent ) ) ) ) Spacer(modifier = Modifier.height(AppSpacing.xs)) // Partner name Text( text = "with ${event.partnerName}", style = AppTypography.body, color = AppColors.secondaryText ) } } @Composable private fun DescriptionSection(description: String) { Box( modifier = Modifier .fillMaxWidth() .padding(horizontal = AppSpacing.md, vertical = AppSpacing.sm) ) { Text( text = description, style = AppTypography.body, color = AppColors.primaryText, textAlign = TextAlign.Center, lineHeight = 22.sp, modifier = Modifier .fillMaxWidth() .clip(RoundedCornerShape(AppSpacing.cornerRadius)) .background(AppColors.surfaceSubtle) .padding(AppSpacing.md) ) } } @Composable private fun ChoiceCard( choice: EventChoice, isSelected: Boolean, canAfford: Boolean, isProcessing: Boolean, eventTypeConfig: EventTypeConfig, onClick: () -> Unit ) { val scale by animateFloatAsState( targetValue = if (isSelected) 0.98f else 1f, animationSpec = spring(dampingRatio = 0.6f), label = "choiceScale" ) val backgroundColor = if (isSelected) { Brush.linearGradient( colors = listOf( eventTypeConfig.iconColor.copy(alpha = 0.25f), eventTypeConfig.iconColor.copy(alpha = 0.15f) ) ) } else { Brush.linearGradient( colors = listOf( AppColors.surfaceElevated, AppColors.background.copy(alpha = 0.8f) ) ) } Card( modifier = Modifier .fillMaxWidth() .scale(scale) .alpha(if (canAfford) 1f else 0.5f) .clickable(enabled = canAfford && !isProcessing, onClick = onClick), shape = RoundedCornerShape(AppSpacing.cornerRadius), colors = CardDefaults.cardColors(containerColor = Color.Transparent), border = androidx.compose.foundation.BorderStroke( width = if (isSelected) 2.dp else 1.5.dp, color = if (isSelected) eventTypeConfig.iconColor.copy(alpha = 0.6f) else AppColors.secondaryText.copy(alpha = 0.2f) ) ) { Column( modifier = Modifier .background(backgroundColor) .padding(AppSpacing.md) ) { // Choice text Text( text = choice.text, style = AppTypography.headline, color = AppColors.primaryText ) Spacer(modifier = Modifier.height(AppSpacing.sm)) Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically ) { // Affinity change Row( horizontalArrangement = Arrangement.spacedBy(AppSpacing.xs), verticalAlignment = Alignment.CenterVertically ) { Icon( imageVector = if (choice.affinityChange >= 0) Icons.Default.Favorite else Icons.Default.HeartBroken, contentDescription = null, tint = if (choice.affinityChange >= 0) AppColors.success else AppColors.error, modifier = Modifier.size(14.dp) ) Text( text = "${if (choice.affinityChange >= 0) "+" else ""}${choice.affinityChange} Affinity", style = AppTypography.caption, color = if (choice.affinityChange >= 0) AppColors.success else AppColors.error ) } // Costs if (choice.energyCost == 0 && choice.moneyCost == 0.0 && choice.diamondCost == 0) { Text( text = "Free", style = AppTypography.captionBold, color = AppColors.success ) } else { Row( horizontalArrangement = Arrangement.spacedBy(AppSpacing.sm), verticalAlignment = Alignment.CenterVertically ) { if (choice.energyCost > 0) { CostBadge( icon = Icons.Default.Bolt, value = choice.energyCost, color = AppColors.energy ) } if (choice.moneyCost > 0) { CostBadge( icon = Icons.Default.AttachMoney, value = choice.moneyCost.toInt(), color = AppColors.money ) } if (choice.diamondCost > 0) { CostBadge( icon = Icons.Default.Diamond, value = choice.diamondCost, color = AppColors.diamond ) } } } } } } } @Composable private fun CostBadge( icon: ImageVector, value: Int, color: Color ) { Row( horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically ) { Icon( imageVector = icon, contentDescription = null, tint = color, modifier = Modifier.size(14.dp) ) Text( text = "$value", style = AppTypography.caption, color = AppColors.primaryText ) } } // Helper data class for event type configuration private data class EventTypeConfig( val icon: ImageVector, val iconColor: Color, val backgroundColor: Color ) private fun getEventTypeConfig(type: RelationshipEventType): EventTypeConfig { return when (type) { RelationshipEventType.ARGUMENT -> EventTypeConfig( icon = Icons.Default.Warning, iconColor = AppColors.warning, backgroundColor = AppColors.warning.copy(alpha = 0.1f) ) RelationshipEventType.ANNIVERSARY -> EventTypeConfig( icon = Icons.Default.Favorite, iconColor = AppColors.primary, backgroundColor = AppColors.primary.copy(alpha = 0.1f) ) RelationshipEventType.JEALOUSY -> EventTypeConfig( icon = Icons.Default.Visibility, iconColor = AppColors.error, backgroundColor = AppColors.error.copy(alpha = 0.1f) ) RelationshipEventType.PROPOSAL -> EventTypeConfig( icon = Icons.Default.Diamond, iconColor = AppColors.success, backgroundColor = AppColors.success.copy(alpha = 0.1f) ) RelationshipEventType.BREAKUP_THREAT -> EventTypeConfig( icon = Icons.Default.HeartBroken, iconColor = AppColors.error, backgroundColor = AppColors.error.copy(alpha = 0.1f) ) } }