/// <summary>
        /// Business Requirements:
        /// 1. Should not create account if email is in use.
        /// 2. Should use repository to get new user model.
        /// 3. Should call Create on repository.
        /// 4. Should call Save on repository.
        /// 5. Should assign email, first name, and last name to new user model.
        /// 6. Should setup new credentials.
        /// </summary>
        public UserAccount CreateAccount(UserAccount newAccount, Credentials newCredentials)
        {
            VerifyEmailIsntInUse(newAccount);

            var newUser = _userCreator.New();
            newUser.Email = newAccount.Email;
            newUser.FirstName = newAccount.FirstName;
            newUser.LastName = newAccount.LastName;

            _userCreator.Create(newUser);
            _userCreator.Save();

            var userAccount = _translateDataUserToUserAccount.Translate(newUser);

            _userAuthProvider.SetupNewCredentials(userAccount, newCredentials);

            return userAccount;
        }
        public void Should_Return_Account()
        {
            //Data Layer Arrange
            var dataUser = new User
            {
                CreationDate = new DateTime(2000, 01, 20),
                Email = "*****@*****.**",
                FirstName = "Jack",
                LastName = "Hoffman",
                UserId = "551581bf90eb291bd0e97fb2",
                LastLogin = new DateTime(2012, 10, 31)
            };

            MockRetrievableUserById
                .Setup(x => x.Retrieve(It.IsAny<ByUserId>()))
                .Returns(dataUser);

            MockRetrievableUserByEmail
                .Setup(x => x.Retrieve(It.IsAny<ByUserEmail>()))
                .Returns(dataUser);

            MockRetrievableAuthyId
                .Setup(x => x.RetrieveAll(It.IsAny<ByEncodedUserId>()))
                .Returns(new List<UserAuthentication>
                {
                    new UserAuthentication
                    {
                        AccountActive = true,
                        AccountType = AccountType.ActualAccount,
                        EncodedPassword = "******",
                        EncodedUserId = "Yvf08ew7hUptyomgslYIYhQmJ+jhUM/nrgQtbJgnW50=",
                        EncryptionKey = "ApplePear",
                        FailedLoginAttemptCount = 0
                    },
                    new UserAuthentication
                    {
                        AccountActive = true,
                        AccountType = AccountType.Trap1Account,
                        EncodedPassword = "******",
                        EncodedUserId = "Yvf08ew7hUptyomgslYIYhQmJ+jhUM/nrgQtbJgnW50=",
                        EncryptionKey = "PearBanana",
                        FailedLoginAttemptCount = 0
                    },
                    new UserAuthentication
                    {
                        AccountActive = true,
                        AccountType = AccountType.Trap2Account,
                        EncodedPassword = "******",
                        EncodedUserId = "Yvf08ew7hUptyomgslYIYhQmJ+jhUM/nrgQtbJgnW50=",
                        EncryptionKey = "BananaGrape",
                        FailedLoginAttemptCount = 0
                    },
                    new UserAuthentication
                    {
                        AccountActive = true,
                        AccountType = AccountType.Trap3Account,
                        EncodedPassword = "******",
                        EncodedUserId = "Yvf08ew7hUptyomgslYIYhQmJ+jhUM/nrgQtbJgnW50=",
                        EncryptionKey = "GrapeApple",
                        FailedLoginAttemptCount = 0
                    }
                });

            //arrange
            MockSystemTime
                .Setup(x => x.Current())
                .Returns(new DateTime(2015, 12, 2, 0, 0, 0, DateTimeKind.Utc));

            var input = new Credentials
            {
                Email = "*****@*****.**",
                Password = "******"
            };

            var expected = new UserAccount
            {
                Email = "*****@*****.**",
                FirstName = "Jack",
                LastName = "Hoffman",
                UserId = "551581bf90eb291bd0e97fb2"
            };

            UserAccount actual;

            //act
            actual = Subject.RetrieveAccount(input);

            //assert
            Assert.AreEqual(expected.Email, actual.Email, string.Format("Expected Email of {0}, actual was {1}", expected.Email, actual.Email));
            Assert.AreEqual(expected.FirstName, actual.FirstName, string.Format("Expected FirstName of {0}, actual was {1}", expected.FirstName, actual.FirstName));
            Assert.AreEqual(expected.LastName, actual.LastName, string.Format("Expected LastName of {0}, actual was {1}", expected.LastName, actual.LastName));
            Assert.AreEqual(expected.UserId, actual.UserId, string.Format("Expected UserId of {0}, actual was {1}", expected.UserId, actual.UserId));
        }
        public void DeleteAccount(UserAccount existingAccount, Credentials existCredentials)
        {
            var authenticationResult = _userAuthProvider.Authenticate(existCredentials);
            if (authenticationResult.WasSuccessful)
            {
                _userAuthProvider.DeleteCredentials(existCredentials);

                var query = new ByUserId
                {
                    UserId = existingAccount.UserId
                };

                var existingUser = _userGetByUserId.Retrieve(query);
                _userDeleter.Delete(existingUser);
            }
        }
        /// <summary>
        /// Buisness Requirements:
        /// 1. Verify if Email address is in use.
        /// 2. If it is in use, throw exception.
        /// 3. Exception message should include email that was found to be in use.
        /// 4. If not in use, do nothing.
        /// </summary>
        public void VerifyEmailIsntInUse(UserAccount newAccount)
        {
            var query = new ByUserEmail
            {
                UserEmail = newAccount.Email
            };

            var userDetails = _retrieveUserByEmail.Retrieve(query);

            if (userDetails == null) throw new ArgumentException("Email Address: {0} already in use.", newAccount.Email);
        }
        public UserAccount UpdateAccount(UserAccount existingAccount, Credentials existCredentials)
        {
            var query = new ByUserId
            {
                UserId = existingAccount.UserId
            };

            var updatedUser = _userGetByUserId.Retrieve(query);

            updatedUser.Email = existingAccount.Email;
            updatedUser.FirstName = existingAccount.FirstName;
            updatedUser.LastName = existingAccount.LastName;

            _userUpdater.Update(updatedUser);
            _userUpdater.Save();

            return _translateDataUserToUserAccount.Translate(updatedUser);
        }
        public void SetupNewCredentials(UserAccount userAccount, Credentials credentials)
        {
            string encodedUserId = EncryptionHandler.Encrypt(userAccount.UserId, userAccount.UserId);

            var actualCredentials = _userAuthCreator.New();
            actualCredentials.AccountType = AccountType.ActualAccount;
            actualCredentials.EncodedUserId = encodedUserId;
            actualCredentials.EncodedPassword = EncryptionHandler.Encrypt(credentials.Password, actualCredentials.EncryptionKey);
            _userAuthCreator.Create(actualCredentials);

            var trap1Credentials = _userAuthCreator.New();
            trap1Credentials.AccountType = AccountType.Trap1Account;
            trap1Credentials.EncodedUserId = encodedUserId;
            trap1Credentials.EncodedPassword = EncryptionHandler.Encrypt(_passwords.GeneratePassword(8,2), trap1Credentials.EncryptionKey);
            _userAuthCreator.Create(trap1Credentials);

            var trap2Credentials = _userAuthCreator.New();
            trap2Credentials.AccountType = AccountType.Trap2Account;
            trap2Credentials.EncodedUserId = encodedUserId;
            trap2Credentials.EncodedPassword = EncryptionHandler.Encrypt(_passwords.GeneratePassword(10, 3), trap2Credentials.EncryptionKey);
            _userAuthCreator.Create(trap2Credentials);

            var trap3Credentials = _userAuthCreator.New();
            trap3Credentials.AccountType = AccountType.Trap3Account;
            trap3Credentials.EncodedUserId = encodedUserId;
            trap3Credentials.EncodedPassword = EncryptionHandler.Encrypt(_passwords.GeneratePassword(7, 1), trap3Credentials.EncryptionKey);
            _userAuthCreator.Create(trap3Credentials);
        }