/// <inheritdoc/>
        public override async Task <IEnumerable <RecipeModel> > Handle(GetAllRecipesQuery request, CancellationToken cancellationToken)
        {
            var recipes = await RecipeDomainContext
                          .GetRecipesForUser(request.User)
                          .OrderBy(r => r.Name)
                          .ToListAsync();

            return(recipes.Select(RecipeModel.From));
        }
        /// <inheritdoc/>
        public override async Task <RecipeModel> Handle(GetRecipeByIdQuery request, CancellationToken cancellationToken)
        {
            var recipe = await RecipeDomainContext
                         .GetRecipesForUser(request.User)
                         .FirstOrDefaultAsync(r => r.Id == request.Id);

            return(recipe == null ?
                   throw new RecipeNotFoundException($"No recipe found [ID = {request.Id}]") :
                   RecipeModel.From(recipe));
        }
        public override async Task <RecipeModel> DoHandleRequest(UpdateRecipeRequest request, CancellationToken cancellationToken)
        {
            var recipe = await RecipeDomainContext
                         .GetRecipesForUser(request.User)
                         .FirstOrDefaultAsync(r => r.Id == request.RecipeId);

            if (recipe == null)
            {
                throw new RecipeNotFoundException($"No recipe found [ID = {request.RecipeId}]");
            }

            recipe.Name = request.Name;

            await RecipeDomainContext.SaveChangesAsync();

            return(RecipeModel.From(recipe));
        }
        /// <inheritdoc/>
        public override async Task <RecipeModel> DoHandleRequest(UpdateRecipeGroupsRequest request, CancellationToken cancellationToken)
        {
            var recipe = await RecipeDomainContext
                         .GetRecipesForUser(request.User)
                         .FirstOrDefaultAsync(r => r.Id == request.RecipeId);

            if (recipe == null)
            {
                throw new RecipeNotFoundException($"No recipe found [ID = {request.RecipeId}]");
            }

            // First, create any new recipe groups.
            var newRecipeGroups = await CreateNewRecipeGroups(request);

            // Now, update the recipe group links
            recipe.RecipeGroupLinks = newRecipeGroups.Select(rg => new RecipeGroupLink()
            {
                RecipeId      = recipe.Id,
                RecipeGroupId = rg.Id
            }).ToList();

            foreach (var recipeGroup in request.RecipeGroupsToAssociate)
            {
                recipe.RecipeGroupLinks.Add(new RecipeGroupLink()
                {
                    RecipeId      = recipe.Id,
                    RecipeGroupId = recipeGroup.RecipeGroupId
                });
            }

            await RecipeDomainContext.SaveChangesAsync();

            // Refresh data
            recipe = await RecipeDomainContext
                     .GetRecipesForUser(request.User)
                     .FirstOrDefaultAsync(r => r.Id == request.RecipeId);

            return(RecipeModel.From(recipe));
        }
        public override async Task <Unit> Handle(DeleteRecipeByIdRequest request, CancellationToken cancellationToken)
        {
            var recipeToRemove = await RecipeDomainContext
                                 .GetRecipesForUser(request.User)
                                 .FirstOrDefaultAsync(r => r.Id == request.RecipeId);

            if (recipeToRemove != null)
            {
                // First, remove any cart items associated with ingredients from this recipe.
                var ingredientIds = new HashSet <Guid>(
                    recipeToRemove.Ingredients.Select(i => i.Id));
                var cart = await RecipeDomainContext.GetCurrentCart(request.User);

                cart.Items = cart.Items.Where(ci => !ingredientIds.Contains(ci.Ingredient.Id)).ToList();

                // Now, delete the recipe.
                RecipeDomainContext.Recipes.Remove(recipeToRemove);

                await RecipeDomainContext.SaveChangesAsync();
            }

            return(Unit.Value);
        }
        public override async Task <RecipeModel> DoHandleRequest(UpdateRecipeIngredientsRequest request, CancellationToken cancellationToken)
        {
            var recipe = await RecipeDomainContext
                         .GetRecipesForUser(request.User)
                         .FirstOrDefaultAsync(r => r.Id == request.RecipeId);

            var existingIngredientCategories = await RecipeDomainContext
                                               .IngredientCategories
                                               .ForUser(request.User)
                                               .ToListAsync();

            if (recipe == null)
            {
                throw new RecipeNotFoundException($"No recipe found [ID = {request.RecipeId}]");
            }

            var ingredients = request.Ingredients.Select(i => new Ingredient()
            {
                RecipeId = request.RecipeId,
                Name     = i.Name,
                Amount   = i.Amount,
                // Try to find the existing category, creating a new one if none is found.
                Category = existingIngredientCategories
                           .FirstOrDefault(ic => ic.Name == i.Category) ??
                           new IngredientCategory()
                {
                    Name   = i.Category,
                    UserId = request.User.Id
                }
            });

            recipe.Ingredients = ingredients.ToList();

            await RecipeDomainContext.SaveChangesAsync();

            return(RecipeModel.From(recipe));
        }