public async Task <IHttpActionResult> GetItemsBySubcategory(
            ItemsPagination pagination,
            ItemSubcategoryFilter filter,
            CancellationToken cancellationToken = default)
        {
            var baseQuery = from i in db.Items.AsNoTracking()
                            select i;

            switch (filter.Category)
            {
            case "weapons":
                switch (filter.Subcategory)
                {
                case "bows": baseQuery = baseQuery.Where(w => w.IsBow); break;

                case "broadswords": baseQuery = baseQuery.Where(w => w.IsBroadsword); break;

                case "cats": baseQuery = baseQuery.Where(w => w.IsCat); break;

                case "crossbows": baseQuery = baseQuery.Where(w => w.IsCrossbow); break;

                case "daggers": baseQuery = baseQuery.Where(w => w.IsDagger); break;

                case "flails": baseQuery = baseQuery.Where(w => w.IsFlail); break;

                case "longswords": baseQuery = baseQuery.Where(w => w.IsLongsword); break;

                case "rapiers": baseQuery = baseQuery.Where(w => w.IsRapier); break;

                case "spears": baseQuery = baseQuery.Where(w => w.IsSpear); break;

                case "whips": baseQuery = baseQuery.Where(w => w.IsWhip); break;
                }
                break;

            case "chest":
                switch (filter.Subcategory)
                {
                case "red": baseQuery = baseQuery.Where(i => (i.IsFood || i.IsTorch || i.IsShovel || RedChestSlots.Contains(i.Slot)) && !i.IsScroll); break;

                case "purple": baseQuery = baseQuery.Where(i => i.IsSpell || i.IsScroll || PurpleChestSlots.Contains(i.Slot)); break;

                case "black": baseQuery = baseQuery.Where(i => i.IsArmor || i.IsWeapon || BlackChestSlots.Contains(i.Slot)); break;

                case "mimic": break;         // All items
                }
                break;
            }

            var content = await GetItemsAsync(pagination, baseQuery, cancellationToken);

            return(Ok(content));
        }
            public async Task ReturnsOK(string category, string subcategory)
            {
                // Arrange
                var filter = new ItemSubcategoryFilter
                {
                    Category    = category,
                    Subcategory = subcategory
                };
                var result = await controller.GetItemsBySubcategory(pagination, filter);

                // Assert
                Assert.IsAssignableFrom <OkNegotiatedContentResult <ItemsEnvelope> >(result);
            }
            public async Task ReturnsItemsFilteredBySubcategory(string category, string subcategory, string name)
            {
                // Arrange -> Act
                var filter = new ItemSubcategoryFilter
                {
                    Category    = category,
                    Subcategory = subcategory
                };
                var result = await controller.GetItemsBySubcategory(pagination, filter);

                // Assert
                var contentResult = (OkNegotiatedContentResult <ItemsEnvelope>)result;
                var contentItems  = contentResult.Content.Items;
                var first         = contentItems.First();

                Assert.Equal(name, first.Name);
            }
        /// <summary>
        /// Binds the model to a value by using the specified controller context and binding context.
        /// </summary>
        /// <param name="actionContext">The action context.</param>
        /// <param name="bindingContext">The binding context.</param>
        /// <returns>
        /// true if model binding is successful; otherwise, false.
        /// </returns>
        public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
        {
            var modelState = bindingContext.ModelState;

            var categoryResult = bindingContext.ValueProvider.GetValue("category");
            var category       = categoryResult.ConvertTo <string>();

            switch (category)
            {
            case "weapons":
            case "chest":
                var model = new ItemSubcategoryFilter();
                model.Category = category;
                var subcategoryResult = bindingContext.ValueProvider.GetValue("subcategory");
                var subcategory       = subcategoryResult.ConvertTo <string>();
                switch (category)
                {
                case "weapons":
                    switch (subcategory)
                    {
                    case "bows":
                    case "broadswords":
                    case "cats":
                    case "crossbows":
                    case "daggers":
                    case "flails":
                    case "longswords":
                    case "rapiers":
                    case "spears":
                    case "whips":
                        model.Subcategory    = subcategory;
                        bindingContext.Model = model;
                        return(true);

                    default:
                        modelState.AddModelError("subcategory", $"'{subcategory}' is not a valid subcategory.");
                        return(false);
                    }

                case "chest":
                    switch (subcategory)
                    {
                    case "red":
                    case "purple":
                    case "black":
                    case "mimic":
                        model.Subcategory    = subcategory;
                        bindingContext.Model = model;
                        return(true);

                    default:
                        modelState.AddModelError("subcategory", $"'{subcategory}' is not a valid subcategory.");
                        return(false);
                    }

                // Unreachable
                default:
                    return(false);
                }

            default:
                modelState.AddModelError("category", $"'{category}' is not a valid category.");
                return(false);
            }
        }