public IQueryable<RecipeModel> GetByCategory(int id)
        {

            var context = new RecipesContext();

            //this.CheckSession(context); //no need of authorized access

            var category = context.Categories.FirstOrDefault(c => c.Id == id);
            if (category == null)
            {
                throw new ArgumentException("Not found category with such id","id");
            }
         
           var recipeEntities = context.Categories.FirstOrDefault(c => c.Id == id).Recipes.AsQueryable();

            //var models = recipeEntities.Select(RecipeModel.FromRecipeToRecipeModel);

            var models =
                       (from r in recipeEntities
                        select new RecipeModel()
                        {
                            Title = r.Title,
                            CreatorUser = r.Creator.Username,
                            CategoryName = r.Category.Title,
                            PublishDate = r.PublishDate,
                            Rating = r.Fans.AsQueryable().Count(),
                            Id = r.Id

                        });

            return models;
        }
        public IQueryable<string> GetAll()
        {
            var context = new RecipesContext();

            var recipeEntities = context.Products;
            var model = recipeEntities.OrderBy(x => x.Title)
                .Select(x => x.Title).Distinct();

            return model;
        }
        public IQueryable<CategoryModel> GetAll()
        {

            var context = new RecipesContext();

            var recipeEntities = context.Categories;
            var model = recipeEntities.OrderBy(x => x.Title)
                .Select(CategoryModel.FromCategoryToCategoryModel);

            return model;
        }
        public IQueryable<UserInfoModel> GetAll()
        {
            var dbContext = new RecipesContext();
            var user = GetCurrentUser(dbContext);
            if (user == null || user.Role != Role.Admin)
            {
                throw new InvalidOperationException("Only an authorized admin can view users.");
            }

            var users = dbContext.Users.Select(UserInfoModel.FromUser);
            return users;
        }
        public HttpResponseMessage GetById(int id)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
                 {
                     var context = new RecipesContext();

                     // CheckSession(context);

                     var recipeEntities = context.Recipes.Include("Categories");
                     var model = recipeEntities.Where(x => x.Id == id)
                         .Select(RecipeDetails.FromRecipeToRecipeDetails)
                         .FirstOrDefault();


                     //var model =
                     //(from r in recipeEntities
                     // where r.Id == id
                     // select new RecipeDetails()
                     // {
                     //     Title = r.Title,
                     //     CreatorUser = r.Creator.Username,
                     //     CategoryName = r.Category.Title,
                     //     PublishDate = r.PublishDate,
                     //     Rating = r.Fans.AsQueryable().Count(),
                     //     Id = r.Id,
                     //     Content = r.Content,
                     //     Products = (from p in r.Products
                     //                 select new ProductDetails()
                     //                 {
                     //                     Name = p.Product.Title,
                     //                     Quantity = p.Quantity,
                     //                     Measurement = Enum.GetName(p.Mesaurement.GetType(), p.Mesaurement)
                     //                 }).AsQueryable()

                     // }).FirstOrDefault();

                     if (model == null)
                     {
                         throw new ArgumentException("No such recipe");
                     }

                     var response = this.Request.CreateResponse(HttpStatusCode.OK, model);
                     return response;
                 });

            return responseMsg;
        }
        public HttpResponseMessage GetAll()
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
               {
                   var context = new RecipesContext();

                   var recipeEntities = context.Recipes;
                   var model = recipeEntities
                       .Select(RecipeModel.FromRecipeToRecipeModel);

                   if (model == null)
                   {
                       throw new ArgumentException("No recipes");
                   }

                   var response = this.Request.CreateResponse(HttpStatusCode.OK, model);
                   return response;
               });

            return responseMsg;
        }
        public HttpResponseMessage PostLoginUser(UserModel model)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var dbContext = new RecipesContext();
                using (dbContext)
                {
                    this.ValidateUsername(model.Username);
                    this.ValidateAuthCode(model.AuthCode);

                    var usernameToLower = model.Username.ToLower();

                    var user = dbContext.Users.FirstOrDefault(
                        usr => usr.Username == usernameToLower
                        && usr.AuthCode == model.AuthCode);

                    if (user == null)
                    {
                        throw new InvalidOperationException("Invalid username or password");
                    }

                    if (user.SessionKey == null)
                    {
                        user.SessionKey = this.GenerateSessionKey(user.UserId);
                        dbContext.SaveChanges();
                    }

                    var loggedModel = new LoggedUserModel()
                    {
                        Username = user.Username,
                        SessionKey = user.SessionKey
                    };

                    var response = this.Request.CreateResponse(HttpStatusCode.Created, loggedModel);
                    return response;
                }
            });

            return responseMsg;
        }
        public HttpResponseMessage DeleteUser(int id)
        {
            var dbContext = new RecipesContext();
            using (dbContext)
            {
                var user = GetCurrentUser(dbContext);
                if (user == null || user.Role != Role.Admin)
                {
                    throw new InvalidOperationException("Only an authorized admin can delete users.");
                }

                var userToDelete = dbContext.Users.FirstOrDefault(u => u.UserId == id);

                if (userToDelete != null)
                {
                    dbContext.Users.Remove(userToDelete);
                    dbContext.SaveChanges();
                }

                var response = this.Request.CreateResponse(HttpStatusCode.OK, string.Empty);
                return response;
            }
        }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            Database.SetInitializer(new MigrateDatabaseToLatestVersion<RecipesContext, Configuration>());

            using (RecipesContext context = new RecipesContext())
            {

               

                context.Database.Initialize(true);
            }

            
        }
        public HttpResponseMessage PutLogoutUser()
        {
            var dbContext = new RecipesContext();
            using (dbContext)
            {
                var user =  GetCurrentUser(dbContext);
                if (user != null)
                {
                    user.SessionKey = null;
                    dbContext.SaveChanges();
                }

                var response = this.Request.CreateResponse(HttpStatusCode.NoContent);
                return response;
            }
        }
        public HttpResponseMessage PostRegisterUser(UserModel model)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var dbContext = new RecipesContext();
                using (dbContext)
                {
                    this.ValidateUsername(model.Username);
                    this.ValidateAuthCode(model.AuthCode);

                    var usernameToLower = model.Username.ToLower();

                    var user = dbContext.Users.FirstOrDefault(
                        usr => usr.Username == usernameToLower);

                    if (user != null)
                    {
                        throw new InvalidOperationException("User exists");
                    }

                    user = new User()
                    {
                        Username = model.Username.ToLower(),
                        AuthCode = model.AuthCode,
                        Role = Role.Client
                    };

                    dbContext.Users.Add(user);
                    dbContext.SaveChanges();

                    user.SessionKey = this.GenerateSessionKey(user.UserId);
                    dbContext.SaveChanges();

                    var loggedModel = new LoggedUserModel()
                    {
                        Username = user.Username,
                        SessionKey = user.SessionKey
                    };

                    var response = this.Request.CreateResponse(HttpStatusCode.Created, loggedModel);
                    return response;
                }
            });

            return responseMsg;
        }
        public HttpResponseMessage Add(RecipeDetails recipe)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new RecipesContext();

                var user = GetCurrentUser(context);

                var category = context.Categories.FirstOrDefault(x => x.Title == recipe.CategoryName);

                if (category == null)
                {
                    throw new ArgumentException("No such category");
                }

                var addedRecipe = new Recipe()
                    {
                        Category = category,
                        Content = recipe.Content,
                        Creator = user,
                        PublishDate = DateTime.Now,
                        Title = recipe.Title
                    };

                foreach (var product in recipe.Products)
                {
                    var productToAdd = context.Products.FirstOrDefault(x => x.Title == product.Name);

                    if (productToAdd == null)
                    {
                        productToAdd = new Product { Title = product.Name };
                    }

                    addedRecipe.Products.Add(new Ingredient()
                    {
                        Product = productToAdd,
                        Quantity = product.Quantity,
                        Mesaurement = (Measurement)Enum.Parse(typeof(Measurement), product.Measurement)

                    });
                }

                context.Recipes.Add(addedRecipe);
                context.SaveChanges();

                var response = this.Request.CreateResponse(HttpStatusCode.Created, addedRecipe);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage Delete(int id)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new RecipesContext();

                var user = GetCurrentUser(context);

                var recipe = context.Recipes.FirstOrDefault(x => x.Id == id);

                if (recipe == null)
                {
                    throw new ArgumentException("No such recipe.");
                }

                if (recipe.Creator.UserId != user.UserId && user.Role != Role.Admin)
                {
                    throw new Exception("This user doesn't have the permissions to delete this recipe.");
                }

                context.Recipes.Remove(recipe);
                user.MyRecipes.Remove(recipe);

                context.SaveChanges();
                var response = this.Request.CreateResponse(HttpStatusCode.OK);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage State(int id)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new RecipesContext();

                var sessionKey = this.Request.Headers.GetValues("X-sessionKey").FirstOrDefault();

                //sessionKey = sessionKey.Substring("sessionKey=".Length);
                if (sessionKey == null)
                {
                    throw new InvalidOperationException("No session key found.");
                }

                var user = context.Users.FirstOrDefault(
                    usr => usr.SessionKey == sessionKey);

                if (user == null)
                {
                    StateModel notLoggedUserState = new StateModel() { State = false };
                    var notLoggedUserResponse = this.Request.CreateResponse(HttpStatusCode.OK, notLoggedUserState);
                    return notLoggedUserResponse;
                }

                var recipe = context.Recipes.FirstOrDefault(x => x.Id == id);

                if (recipe == null)
                {
                    throw new ArgumentException("No such recipe");
                }

                StateModel state = new StateModel() { State = recipe.Fans.Contains(user) };

                var response = this.Request.CreateResponse(HttpStatusCode.OK, state);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage Mine()
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new RecipesContext();

                var user = GetCurrentUser(context);

                var favourites = from favourite
                                 in user.MyRecipes
                                 select new RecipeModel()
                                 {
                                     CategoryName = favourite.Category.Title,
                                     CreatorUser = favourite.Creator.Username,
                                     PublishDate = favourite.PublishDate,
                                     Rating = favourite.Fans.Count,
                                     Title = favourite.Title
                                 };
                var response = this.Request.CreateResponse(HttpStatusCode.OK, favourites);
                return response;
            });

            return responseMsg;
        }
        public HttpResponseMessage Like(int id)
        {
            var responseMsg = this.PerformOperationAndHandleExceptions(() =>
            {
                var context = new RecipesContext();

                var user = GetCurrentUser(context);

                var recipe = context.Recipes.FirstOrDefault(x => x.Id == id);

                if (recipe == null)
                {
                    throw new ArgumentException("No such recipe.");
                }

                if (!user.Favorites.Contains(recipe))
                {
                    user.Favorites.Add(recipe);
                    context.SaveChanges();
                }
                var response = this.Request.CreateResponse(HttpStatusCode.NoContent);
                return response;
            });

            return responseMsg;
        }