/// <summary>Will verify the password using <see cref="Password.VerifyPasswordHash(string, string, string)"/></summary>
 /// <param name="user">The user whose password will be verified.</param>
 /// <param name="password">The password to verify.</param>
 /// <exception cref="WrongPasswordException">If the password is wrong.</exception>
 protected static void VerifyPassword(FoodOnlineUser user, string password)
 {
     if (!PasswordHelper.VerifyPassword(password, user.PasswordHash, user.PasswordSalt))
     {
         throw new WrongPasswordException();
     }
 }
        /// <summary>
        /// Will use the provided user and password to fill the hash and salt. The id will be filled
        /// using the <see cref="GenerateId"/> Will return true if the method succeeded.
        /// </summary>
        /// <param name="user">
        /// A user to be saved with all necessary parameters filled except the id. this will be
        /// filled from <see cref="GenerateId"/>
        /// </param>
        /// <param name="password">The password to hash.</param>
        /// <returns>True if the user was stored false otherwise.</returns>
        /// <exception cref="NoPasswordException">No password was provided.</exception>
        /// <exception cref="EmailTakenException">Email already exists.</exception>
        public virtual string Create(string username, string email, string password)
        {
            if (string.IsNullOrWhiteSpace(password))
            {
                throw new NoPasswordException();
            }
            if (context.Users.Any(x => x.Email == email))
            {
                throw new EmailTakenException(email);
            }

            PasswordHelper.CreatePasswordHash(password,
                                              out string passwordHash,
                                              out string passwordSalt);

            var user = new FoodOnlineUser
            {
                Username     = username,
                Email        = email,
                Id           = IdGenerator.Generate(),
                PasswordHash = passwordHash,
                PasswordSalt = passwordSalt
            };

            context.Users.Add(user);
            context.SaveChanges();
            context.Entry(user).State = EntityState.Detached;

            return(user.Id);
        }
        /// <summary>
        /// Update a user's email, username and password inside the database if the value is provided.
        /// </summary>
        /// <param name="userParam">
        /// A user object that should populate the values that need to be update and leave the rest empty.
        /// </param>
        /// <param name="password">The user password..</param>
        /// <param name="newPassword">The new password to change if provided.</param>
        /// <exception cref="FoodOnlineUserNotFoundException">When the user is not found.</exception>
        /// <exception cref="NoPasswordException">When no password is provided.</exception>
        /// <exception cref="WrongPasswordException">When the password provided is wrong.</exception>
        /// <exception cref="EmailTakenException">When the email already exists.</exception>
        public virtual void Update(FoodOnlineUser userParam, string password, string newPassword)
        {
            var user = GetUser(userParam.Id);

            PasswordNotEmpty(password);
            VerifyPassword(user, password !);

            // update email if provided
            if (!string.IsNullOrWhiteSpace(userParam.Email) && userParam.Email != user.Email)
            {
                // throw error if the new email already exists.
                if (context.Users.AsNoTracking().Any(x => x.Email == userParam.Email))
                {
                    throw new EmailTakenException(userParam.Email);
                }

                user.Email = userParam.Email;
            }

            // update username if provided
            if (!string.IsNullOrWhiteSpace(userParam.Username))
            {
                user.Username = userParam.Username;
            }

            // update password if provided
            if (!string.IsNullOrWhiteSpace(newPassword))
            {
                PasswordHelper.CreatePasswordHash(newPassword,
                                                  out string passwordHash,
                                                  out string passwordSalt);

                user.PasswordHash = passwordHash;
                user.PasswordSalt = passwordSalt;
            }

            context.SaveChanges();
            context.Entry(user).State = EntityState.Detached;
        }