package com.example.viewmodel import android.app.Application import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import com.example.data.model.AdminSettings import com.example.data.model.AppNotification import com.example.data.model.CartItem import com.example.data.model.CustomerUser import com.example.data.model.FoodItem import com.example.data.model.Order import com.example.data.model.OrderItemSummary import com.example.data.model.OrderStatus import com.example.data.repository.LoveZoneRepository import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import java.util.UUID import com.example.data.model.FoodReview import kotlinx.coroutines.flow.Flow sealed class CustomerNavScreen { object Home : CustomerNavScreen() object Menu : CustomerNavScreen() object Orders : CustomerNavScreen() object Alerts : CustomerNavScreen() object Account : CustomerNavScreen() object Cart : CustomerNavScreen() object Checkout : CustomerNavScreen() data class TrackOrder(val orderId: String) : CustomerNavScreen() } class CustomerViewModel(application: Application) : AndroidViewModel(application) { val repository = LoveZoneRepository.getInstance(application) val adminSettings: StateFlow = repository.adminSettings val currentUser: StateFlow = repository.currentUser val allFoodItems: StateFlow> = repository.foodItems .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val allOrders: StateFlow> = repository.customerOrders .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val allNotifications: StateFlow> = repository.notifications .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) val allReviews: StateFlow> = repository.allReviews .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) // Navigation State private val _currentScreen = MutableStateFlow(CustomerNavScreen.Home) val currentScreen: StateFlow = _currentScreen.asStateFlow() init { viewModelScope.launch { while (true) { repository.syncCentralCloudOrders() kotlinx.coroutines.delay(4000) } } } // Filters for Menu / Home val searchQuery = MutableStateFlow("") val selectedCategory = MutableStateFlow("All") val selectedDietFilter = MutableStateFlow("All") // "All", "Veg", "Non-Veg" // Filtered items val filteredFoodItems: StateFlow> = combine( allFoodItems, searchQuery, selectedCategory, selectedDietFilter ) { items, query, category, diet -> items.filter { item -> val matchesQuery = query.isBlank() || item.name.contains(query, ignoreCase = true) || item.category.contains(query, ignoreCase = true) || item.description.contains(query, ignoreCase = true) val matchesCategory = category == "All" || item.category.equals(category, ignoreCase = true) val matchesDiet = when (diet) { "Veg" -> item.isVeg "Non-Veg" -> !item.isVeg else -> true } matchesQuery && matchesCategory && matchesDiet } }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList()) // Cart State private val _cartItems = MutableStateFlow>(emptyMap()) val cartItems: StateFlow> = _cartItems.asStateFlow() val couponCode = MutableStateFlow("") val couponDiscount = MutableStateFlow(0.0) val cookingInstruction = MutableStateFlow("") val selectedPaymentMethod = MutableStateFlow("PAYTM") // "PAYTM", "GPAY", "PHONEPE", "UPI_QR", "CASH_ON_DELIVERY" val upiUtrInput = MutableStateFlow("") private val _orderPlacedEvent = MutableSharedFlow() val orderPlacedEvent: SharedFlow = _orderPlacedEvent.asSharedFlow() val cartTotalCount: StateFlow = _cartItems.combine(_cartItems) { map, _ -> map.values.sumOf { it.quantity } }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0) val cartItemTotal: StateFlow = _cartItems.combine(_cartItems) { map, _ -> map.values.sumOf { it.subtotal } }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0.0) val deliveryFee: StateFlow = combine(cartItemTotal, adminSettings) { total, settings -> if (total == 0.0 || total >= settings.freeDeliveryThreshold) 0.0 else settings.deliveryFee }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0.0) val grandTotal: StateFlow = combine( cartItemTotal, deliveryFee, couponDiscount ) { items, fee, discount -> val total = items + fee - discount if (total < 0) 0.0 else total }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), 0.0) fun navigateTo(screen: CustomerNavScreen) { _currentScreen.value = screen } fun addToCart(item: FoodItem) { val current = _cartItems.value.toMutableMap() val existing = current[item.id] if (existing != null) { current[item.id] = existing.copy(quantity = existing.quantity + 1) } else { current[item.id] = CartItem(item = item, quantity = 1) } _cartItems.value = current } fun decrementOrRemoveFromCart(item: FoodItem) { val current = _cartItems.value.toMutableMap() val existing = current[item.id] ?: return if (existing.quantity > 1) { current[item.id] = existing.copy(quantity = existing.quantity - 1) } else { current.remove(item.id) } _cartItems.value = current } fun clearCart() { _cartItems.value = emptyMap() couponDiscount.value = 0.0 couponCode.value = "" cookingInstruction.value = "" upiUtrInput.value = "" } fun applyCoupon(code: String): String { val clean = code.trim().uppercase() val itemTotal = cartItemTotal.value return if (clean == "LOVE50") { val discount = (itemTotal * 0.5).coerceAtMost(100.0) couponDiscount.value = discount couponCode.value = "LOVE50" "Coupon applied! You saved ₹${discount.toInt()}" } else if (clean == "FLAT20") { val discount = 20.0.coerceAtMost(itemTotal) couponDiscount.value = discount couponCode.value = "FLAT20" "Coupon applied! ₹20 OFF" } else { "Invalid coupon code. Try LOVE50" } } fun removeCoupon() { couponCode.value = "" couponDiscount.value = 0.0 } fun placeOrder( customPaymentStatus: String? = null, customUpiTxnId: String? = null, onSuccess: (Order) -> Unit ) { val itemsList = _cartItems.value.values.map { OrderItemSummary( foodName = it.item.name, quantity = it.quantity, price = it.item.price, isVeg = it.item.isVeg ) } if (itemsList.isEmpty()) return val user = currentUser.value val uniqueId = "OD-LZ-" + UUID.randomUUID().toString().substring(0, 8).uppercase() val paymentStatusToUse = customPaymentStatus ?: if (selectedPaymentMethod.value == "CASH_ON_DELIVERY") "CASH_ON_DELIVERY" else "CUSTOMER_PAYMENT_RECEIVED" val txnIdToUse = customUpiTxnId ?: if (selectedPaymentMethod.value != "CASH_ON_DELIVERY") (upiUtrInput.value.ifBlank { "${selectedPaymentMethod.value}-$uniqueId" }) else "" val order = Order( orderId = uniqueId, customerName = user.name, customerPhone = user.phone, deliveryAddress = user.address, items = itemsList, itemTotal = cartItemTotal.value, deliveryFee = deliveryFee.value, discount = couponDiscount.value, grandTotal = grandTotal.value, paymentMethod = selectedPaymentMethod.value, paymentStatus = paymentStatusToUse, upiTransactionId = txnIdToUse, orderStatus = OrderStatus.PLACED, timestamp = System.currentTimeMillis() ) viewModelScope.launch { repository.placeOrder(order) clearCart() _orderPlacedEvent.emit(order) onSuccess(order) } } fun placeOrder(onSuccess: (Order) -> Unit) { placeOrder(null, null, onSuccess) } suspend fun isUtrAlreadyUsed(utr: String): Boolean { return repository.isUtrAlreadyUsed(utr) } fun repeatOrder(order: Order) { val allItemsMap = allFoodItems.value.associateBy { it.name } for (orderedItem in order.items) { val matched = allItemsMap[orderedItem.foodName] if (matched != null) { repeat(orderedItem.quantity) { addToCart(matched) } } } navigateTo(CustomerNavScreen.Cart) } fun markNotificationsRead() { viewModelScope.launch { repository.markNotificationsRead() } } fun updateProfilePicture(uri: String) { viewModelScope.launch { repository.updateProfilePicture(uri) } } fun getReviewsForFoodItem(foodItemId: Long): Flow> { return repository.getReviewsForFoodItem(foodItemId) } fun submitFoodReview(foodItemId: Long, foodName: String, rating: Float, reviewText: String, onSuccess: () -> Unit = {}) { val user = currentUser.value val review = FoodReview( foodItemId = foodItemId, foodName = foodName, customerName = if (user.isLoggedIn && user.name.isNotBlank()) user.name else "Customer", customerPhone = user.phone, rating = rating, reviewText = reviewText.trim(), timestamp = System.currentTimeMillis() ) viewModelScope.launch { repository.submitFoodReview(review) onSuccess() } } fun submitFoodReview(foodItem: FoodItem, rating: Float, reviewText: String, onSuccess: () -> Unit = {}) { submitFoodReview(foodItem.id, foodItem.name, rating, reviewText, onSuccess) } fun verifyAndCompleteOnlinePayment(orderId: String, upiTxnId: String, onSuccess: () -> Unit = {}) { viewModelScope.launch { repository.verifyAndCompleteOnlinePayment(orderId, upiTxnId) onSuccess() } } }