/// <summary>
        /// Add new movie
        /// </summary>
        /// <param name="movie">Movie object</param>
        /// <returns>Result object</returns>
        public BLResult <Movie> AddMovie(Movie movie)
        {
            DBResult <Movie> dbResult;
            BLResult <Movie> result = new BLResult <Movie>();

            // Validating aditional input data
            if (movie == null || movie.SalePrice == null || movie.RentalPrice == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Adding movie
            dbResult = movieDataAccess.CreateMovie(movie);
            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = dbResult.Item;
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Add Sale
        /// </summary>
        /// <param name="sake">Sale object</param>
        /// <returns>Result object</returns>
        public BLResult <Sale> AddSale(Sale sale)
        {
            DBResult <Inventory> inventoryResult;
            DBResult <Sale>      saleResult;
            DBResult <Movie>     movieResult;
            BLResult <Sale>      result = new BLResult <Sale>();


            // Validating input data
            if (sale == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating inventory
            inventoryResult = inventoryDataAccess.GetInventoryById(sale.IdInventory);
            if (!inventoryResult.Success)
            {
                result.Message = "Invalid inventory";
                return(result);
            }
            // Getting current sale price
            movieResult = movieDataAccess.GetMovieById(inventoryResult.Item.IdMovie);
            if (!movieResult.Success)
            {
                result.Message = $"Error getting price from Movie: {movieResult.Message}";
                return(result);
            }

            if (inventoryResult.Item.IsNew == false || inventoryResult.Item.IsAvailable == false)
            {
                result.Message = "Inventory not found or not available";
                return(result);
            }

            sale.SalePrice = movieResult.Item.SalePrice;
            sale.SaleDate  = DateTime.Now;
            // Adding sale
            saleResult = saleDataAccess.CreateSale(sale);
            if (saleResult.Success)
            {
                result.Success = true;
                result.Item    = sale;

                // If the operation is successful the item will no longer be available
                inventoryResult = inventoryDataAccess.SetAvailability(sale.IdInventory, false);
                if (!inventoryResult.Success)
                {
                    result.Message = inventoryResult.Message;
                }
                result.Success = true;
            }
            else
            {
                result.Message = saleResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Put a like
        /// </summary>
        /// <param name="liked">Liked object</param>
        /// <returns>Result object</returns>
        public BLResult <Liked> PutLike(Liked liked)
        {
            DBResult <Liked> dbResult;
            DBResult <Movie> movieResult;
            DBResult <User>  userResult;
            BLResult <Liked> result = new BLResult <Liked>();


            // Validating input data
            if (liked == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating user
            userResult = userDataAccess.GetUserById(liked.IdUser);
            if (!userResult.Success)
            {
                result.Message = "Invalid user";
                return(result);
            }

            // Check that it has not been liked before
            if (!likedDataAccess.HasALike(liked))
            {
                // Adding like
                dbResult = likedDataAccess.CreateLiked(liked);
                if (dbResult.Success)
                {
                    result.Success = true;
                    result.Item    = liked;

                    // Increment like counter
                    movieResult = movieDataAccess.IncrementLikesCounter(liked.IdMovie, 1);
                    if (!movieResult.Success)
                    {
                        result.Success = false;
                        result.Message = movieResult.Message;
                    }
                }
                else
                {
                    result.Message = dbResult.Message;
                }
            }
            else
            {
                // If it exists continue
                result.Success = true;
                result.Item    = liked;
            }

            return(result);
        }
        /// <summary>
        /// Return rental
        /// </summary>
        /// <param name="rental">Rental Object</param>
        /// <returns>Result object</returns>
        public BLResult <Rental> ReturnRental(Rental rental, int currentuser)
        {
            DBResult <Inventory> inventoryResult;
            DBResult <Rental>    dbResult;
            BLResult <Rental>    result = new BLResult <Rental>();

            // Validating inventory
            inventoryResult = inventoryDataAccess.GetInventoryById(rental.IdInventory);
            if (!inventoryResult.Success)
            {
                result.Message = "Invalid inventory";
                return(result);
            }
            // Getting rental
            dbResult = rentalDataAccess.GetRentalById(rental.IdRental);
            if (!dbResult.Success)
            {
                result.Message = "Invalid Rental";
                return(result);
            }
            // validating user
            if (dbResult.Item.IdUser != currentuser)
            {
                result.Message = "Now allowed for corrent user.";
                return(result);
            }

            // Updating rental
            dbResult = rentalDataAccess.ReturnRental(rental.IdRental);
            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = dbResult.Item;

                // If the operation is successful the item will be available
                inventoryResult = inventoryDataAccess.SetAvailability(rental.IdInventory, true);
                if (!inventoryResult.Success)
                {
                    result.Message = inventoryResult.Message;
                }
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Update an User with Patch Document
        /// </summary>
        /// <param name="patchMovie">Patch document</param>
        /// <param name="idMovie">id Movie</param>
        /// <param name="idUser">id User</param>
        /// <returns>Result</returns>
        public async Task <BLResult <Movie> > PatchMovie(JsonPatchDocument <Movie> patchMovie, int idMovie, int idUser)
        {
            DBResult <Movie>         dbResult;
            DBResult <AuditMovieLog> dbResultAudit;
            BLResult <Movie>         result = new BLResult <Movie>();

            // Validating input data
            if (patchMovie == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating allowed operations
            var op = patchMovie.Operations.Where(o => o.path.Equals("/Image") || o.path.Equals("/LikesCounter")).Count();

            if (op > 0)
            {
                result.Message = "Patch operation not allowed";
                return(result);
            }

            // Patchin user
            dbResult = await movieDataAccess.PatchMovie(patchMovie, idMovie);

            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = dbResult.Item;

                // Adding Audit Log
                dbResultAudit = movieDataAccess.AddAuditLog(dbResult.Item, idUser);
                if (!dbResult.Success)
                {
                    // Only return message
                    result.Message = dbResultAudit.Message;
                }
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Add new inventory
        /// </summary>
        /// <param name="liked">Liked object</param>
        /// <returns>Result object</returns>
        public BLResult <Inventory> AddInventory(Inventory inventory)
        {
            DBResult <Inventory> dbResult;
            DBResult <Movie>     movieResult;
            BLResult <Inventory> result = new BLResult <Inventory>();


            // Validating input data
            if (inventory == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating movie
            movieResult = movieDataAccess.GetMovieById(inventory.IdMovie);
            if (!movieResult.Success)
            {
                result.Message = "Invalid movie";
                return(result);
            }

            // Adding Inventory
            dbResult = inventoryDataAccess.CreateInventory(inventory);
            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = inventory;

                // Increment Stock counter
                movieResult = movieDataAccess.IncrementStockCounter(inventory.IdMovie, 1);
                if (!movieResult.Success)
                {
                    result.Success = false;
                    result.Message = movieResult.Message;
                }
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Get one movie
        /// </summary>
        /// <param name="movie">Id movie</param>
        /// <returns>Result object</returns>
        public BLResult <Movie> GetMovieById(int idMovie)
        {
            DBResult <Movie> dbResult;
            BLResult <Movie> result = new BLResult <Movie>();

            // Try to get movie
            dbResult = movieDataAccess.GetMovieById(idMovie);
            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = dbResult.Item;
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Authenticate user and generate JWT
        /// </summary>
        /// <param name="simpleUser">Simple user object</param>
        /// <returns>Result object</returns>
        public BLResult <SimpleUser> Authenticate(SimpleUser simpleUser)
        {
            BLResult <SimpleUser> result = new BLResult <SimpleUser>();

            // Validating input data
            if (simpleUser == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Getting user from database
            DBResult <User> dbResult = userDataAccess.GetUser(simpleUser.Email);

            if (dbResult.Success == true)
            {
                // Valdiating user password
                bool verified, needsUpgrade;
                (verified, needsUpgrade) = passwordHasher.Check(dbResult.Item.Password, simpleUser.Password);

                if (verified && needsUpgrade == false)
                {
                    // Generate Token
                    simpleUser.Token = userService.GenerateToken(dbResult.Item.IdUser, dbResult.Item.Profile);
                    // We should not return the password
                    simpleUser.Password = string.Empty;
                    simpleUser.Profile  = dbResult.Item.Profile;
                    simpleUser.IdUser   = dbResult.Item.IdUser;
                    result.Success      = true;
                    result.Item         = simpleUser;
                }
                else
                {
                    result.Message = "Invalid Password";
                }
            }
            else
            {
                result.Message = dbResult.Message;
            }
            return(result);
        }
        /// <summary>
        /// Get specifict user by id
        /// </summary>
        /// <param name="idUser">Id User</param>
        /// <returns>Result object</returns>
        public BLResult <User> GetUserById(int idUser)
        {
            DBResult <User> dbResult;
            BLResult <User> result = new BLResult <User>();

            // Search user
            dbResult = userDataAccess.GetUserById(idUser);
            if (dbResult.Success)
            {
                // We should not return the password
                result.Success       = true;
                result.Item          = dbResult.Item;
                result.Item.Password = String.Empty;
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Add new user
        /// </summary>
        /// <param name="user">User object</param>
        /// <returns>Result object</returns>
        public BLResult <User> AddUser(User user)
        {
            DBResult <User> dbResult;
            BLResult <User> result = new BLResult <User>();

            // Validating input data
            if (user == null || string.IsNullOrEmpty(user.Email) || string.IsNullOrEmpty(user.Password))
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating repeated email
            dbResult = userDataAccess.GetUser(user.Email);
            if (dbResult.Success == true)
            {
                result.Message = "Email has already been registered";
                return(result);
            }

            // Hashing password
            user.Password = passwordHasher.Hash(user.Password);
            user.IsActive = true;

            // Adding user
            dbResult = userDataAccess.CreateUser(user);
            if (dbResult.Success)
            {
                // We should not return the password
                result.Success       = true;
                result.Item          = dbResult.Item;
                result.Item.Password = String.Empty;
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Update an User with Patch Document
        /// </summary>
        /// <param name="patchUser">Patch document</param>
        /// <param name="idUser">id User</param>
        /// <returns>Result</returns>
        public async Task <BLResult <User> > PatchUser(JsonPatchDocument <User> patchUser, int idUser)
        {
            DBResult <User> dbResult;
            BLResult <User> result = new BLResult <User>();

            // Validating input data
            if (patchUser == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating allowed operations
            var op = patchUser.Operations.Where(o => o.path.Equals("/Password") || o.path.Equals("/Email")).Count();

            if (op > 0)
            {
                result.Message = "Patch operation not allowed";
                return(result);
            }

            // Patchin user
            dbResult = await userDataAccess.PatchUser(patchUser, idUser);

            if (dbResult.Success)
            {
                // We should not return the password
                result.Success       = true;
                result.Item          = dbResult.Item;
                result.Item.Password = String.Empty;
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Remove a like
        /// </summary>
        /// <param name="liked">Liked object</param>
        /// <returns>Result object</returns>
        public BLResult <Liked> RemoveLike(Liked liked)
        {
            DBResult <Liked> dbResult;
            DBResult <Movie> movieResult;
            BLResult <Liked> result = new BLResult <Liked>();

            // Validating input data
            if (liked == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Removing like
            dbResult = likedDataAccess.DeleteLiked(liked);
            if (dbResult.Success)
            {
                result.Success = true;
                result.Item    = liked;

                if (dbResult.Message.Equals("YES"))
                {
                    // Decrement like counter
                    movieResult = movieDataAccess.IncrementLikesCounter(liked.IdMovie, -1);
                    if (!movieResult.Success)
                    {
                        result.Success = false;
                        result.Message = movieResult.Message;
                    }
                }
            }
            else
            {
                result.Message = dbResult.Message;
            }

            return(result);
        }
        /// <summary>
        /// Add Rental
        /// </summary>
        /// <param name="sake">Rental object</param>
        /// <returns>Result object</returns>
        public BLResult <Rental> AddRental(Rental rental)
        {
            DBResult <Inventory> inventoryResult;
            DBResult <Rental>    rentalResult;
            DBResult <Movie>     movieResult;
            BLResult <Rental>    result = new BLResult <Rental>();


            // Validating input data
            if (rental == null)
            {
                result.Message = "Invalid data";
                return(result);
            }

            // Validating inventory
            inventoryResult = inventoryDataAccess.GetInventoryById(rental.IdInventory);
            if (!inventoryResult.Success)
            {
                result.Message = "Invalid inventory";
                return(result);
            }
            // Getting current rental price
            movieResult = movieDataAccess.GetMovieById(inventoryResult.Item.IdMovie);
            if (!movieResult.Success)
            {
                result.Message = $"Error getting price from Movie: {movieResult.Message}";
                return(result);
            }

            if (inventoryResult.Item.IsNew == true || inventoryResult.Item.IsAvailable == false)
            {
                result.Message = "Inventory not found or not available for rent";
                return(result);
            }

            rental.RentalPrice = movieResult.Item.RentalPrice;
            rental.RentalDate  = DateTime.Now;
            rental.ReturnDate  = DateTime.Now.AddDays(7);
            // Adding Rental
            rentalResult = rentalDataAccess.CreateRental(rental);
            if (rentalResult.Success)
            {
                result.Success = true;
                result.Item    = rental;

                // If the operation is successful the item will no longer be available
                inventoryResult = inventoryDataAccess.SetAvailability(rental.IdInventory, false);
                if (!inventoryResult.Success)
                {
                    result.Message = inventoryResult.Message;
                }
                result.Success = true;
            }
            else
            {
                result.Message = rentalResult.Message;
            }

            return(result);
        }