using Microsoft.EntityFrameworkCore; using MealPlanner.Data; using MealPlanner.Models; namespace MealPlanner.Services; public class ShoppingListService(AppDbContext db) { public async Task> GetShoppingListAsync(Guid mealPlanId, string userId) { var plan = await db.MealPlans .Include(p => p.Entries) .ThenInclude(e => e.Recipe) .ThenInclude(r => r.Ingredients) .FirstOrDefaultAsync(p => p.Id == mealPlanId); if (plan is null) return []; if (plan.UserId != userId) throw new UnauthorizedAccessException(); var settings = await db.UserSettings.FindAsync(userId); int householdSize = settings?.HouseholdSize ?? 2; var checkedItems = await db.CheckedShoppingItems .Where(c => c.MealPlanId == mealPlanId && c.UserId == userId) .ToDictionaryAsync(c => c.ItemName.ToLowerInvariant(), c => c.IsChecked); // Aggregate ingredients var aggregated = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var entry in plan.Entries) { foreach (var ing in entry.Recipe.Ingredients) { var key = ing.Name.Trim().ToLowerInvariant(); if (!aggregated.TryGetValue(key, out var item)) { item = new ShoppingItem { Name = ing.Name.Trim(), Unit = ing.Unit, Category = ing.Category, TotalAmount = null, IsChecked = checkedItems.TryGetValue(key, out var chk) && chk, }; aggregated[key] = item; } if (ing.Amount.HasValue) { item.TotalAmount = (item.TotalAmount ?? 0) + ing.Amount.Value * householdSize; } } } return [.. aggregated.Values.OrderBy(i => i.Category).ThenBy(i => i.Name)]; } public async Task ToggleCheckAsync(Guid mealPlanId, string itemName, string userId) { var plan = await db.MealPlans.FindAsync(mealPlanId); if (plan is null) throw new KeyNotFoundException("Meal plan not found"); if (plan.UserId != userId) throw new UnauthorizedAccessException(); var key = itemName.ToLowerInvariant(); var existing = await db.CheckedShoppingItems .FirstOrDefaultAsync(c => c.MealPlanId == mealPlanId && c.UserId == userId && c.ItemName.ToLower() == key); if (existing is null) { existing = new CheckedShoppingItem { Id = Guid.NewGuid(), MealPlanId = mealPlanId, ItemName = itemName, UserId = userId, IsChecked = true, }; db.CheckedShoppingItems.Add(existing); } else { existing.IsChecked = !existing.IsChecked; } await db.SaveChangesAsync(); return existing; } }