private async Task <Device> PrepareUserDevice(AuthenticationViewModel authModel, User user, string middleName, string securityCardFormatted)
        {
            string debugStr = "";

            var firstName = authModel.FirstName;
            var lastName  = authModel.LastName;

            var demoUser = user?.IsDemo.GetValueOrDefault(false) ?? false;

            //User user = await RestroomUnitOfWork.Get<User>().FirstOrDefaultAsync(m => m.Badge == authModel.Badge && m.FirstName == firstName && m.LastName == lastName);
            //if (user != null && !user.Active)
            //    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $"user is not active. debugStr: {debugStr}");
            //var demoUser = user?.IsDemo ?? false;
            ////var demoUser = await IsDemoUserAsync(authModel.FirstName, authModel.LastName, authModel.Badge);
            ////debugStr = "After getting Demo User: "******"After getting Employee, Found:{(employee != null)}";

            //    if (employee == null)
            //        throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $" User not found. debugStr: {debugStr}");
            //    if (!string.Equals(employee.FirstName, firstName, StringComparison.OrdinalIgnoreCase) || !string.Equals(employee.LastName, lastName, StringComparison.OrdinalIgnoreCase))
            //        throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $" User names are not match. debugStr: {debugStr}");
            //    middleName = employee.MiddleName;
            //    securityCardFormatted = employee.SecurityCardFormatted;
            //}


            try
            {
                var device = await RestroomUnitOfWork.Get <Device>().FirstOrDefaultAsync(m => m.DeviceGuid == authModel.DeviceGuid);

                debugStr = $"after getting device and user. DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}";

                if (device != null && !device.Active)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $" device is not Active.", debugStr);
                }
                if (!demoUser && device != null && device.Confirm2FAExpires != null && device.Confirm2FAExpires > DateTime.Now)
                {
                    throw new FriendlyException(FriendlyExceptionType.UnExpiredValid2FAuth, $" device has an unexpired security code. new code can't be generated unless the previous code expires.", debugStr);
                }


                UserDevice userDevice = null;
                if (user != null && device != null)
                {
                    userDevice = await RestroomUnitOfWork.Get <UserDevice>()
                                 .FirstOrDefaultAsync(m => m.DeviceId == device.DeviceId && m.UserId == user.UserId);
                }
                if (device == null)
                {
                    device = new Device
                    {
                        Active      = true,
                        DeviceGuid  = authModel.DeviceGuid,
                        DeviceModel = authModel.DeviceModel,
                        DeviceOS    = authModel.DeviceOS,
                        LastUsed    = DateTime.Now
                    };
                }

                device.DeviceSessionId = Guid.NewGuid().ToString();
                //device.PhoneNumber = authModel.PhoneNumber;
                device.Confirm2FACode    = GenerateRandomCode(6);
                device.Confirm2FAExpires = DateTime.Now.AddMinutes(ValidInMinutes2FactAuth);
                device.Confirmed2FACode  = false;
                device.LastUsed          = DateTime.Now;

                if (user == null)
                {
                    user = new User
                    {
                        Active = true,
                        Badge  = authModel.Badge,
                    };
                }

                user.SecurityCardFormatted = securityCardFormatted;
                user.FirstName             = firstName;
                user.LastName   = lastName;
                user.MiddleName = middleName;



                user     = RestroomUnitOfWork.PrepUser(user);
                device   = RestroomUnitOfWork.PrepDevice(device);
                debugStr = $"Before SaveChanges on user and device. DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}";

                await RestroomUnitOfWork.SaveChangesAsync();

                if (userDevice == null)
                {
                    userDevice        = new UserDevice();
                    userDevice.Active = true;
                }

                userDevice.LastLogon = DateTime.Now;
                userDevice.UserId    = user.UserId;
                userDevice.DeviceId  = device.DeviceId;

                debugStr = $"Before SaveChanges on userDevice. DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}";
                await RestroomUnitOfWork.SaveUserDeviceAsync(userDevice);

                return(device);
            }
            catch (FriendlyException ex)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new Exception("Inside PrepareUserDevice, " + debugStr, ex);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="operatorInfo"></param>
        /// <returns></returns>
        /// <exception cref="FriendlyException"></exception>
        public async Task <OperatorInfoViewModel> GetOperatorInfoAsync(OperatorInfoViewModel operatorInfo)
        {
            string debugStr = "";

            Logger.WriteDebug("GetOperatorInfoAsync called.");

            try
            {
                if (!operatorInfo.Agreed)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                }

                if (string.IsNullOrWhiteSpace(operatorInfo.DeviceGuid))
                {
                    throw new FriendlyException(FriendlyExceptionType.DeviceIsNotSupported);
                }

                if (!operatorInfo.Validating && string.IsNullOrWhiteSpace(operatorInfo.Badge))
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                }

                //if (!operatorInfo.Validating && string.IsNullOrWhiteSpace(operatorInfo.CardNumber))
                //    throw new FriendlyException(FriendlyExceptionType.AccessDenied);


                if (operatorInfo.Validating && string.IsNullOrWhiteSpace(operatorInfo.DeviceSessionId))
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedSessionMismatch);
                }

                // --------------------------------------some sanity check!
                if ((operatorInfo.FirstName?.Length ?? 0) > 255)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied, "FirstName is too long.");
                }
                if ((operatorInfo.LastName?.Length ?? 0) > 255)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied, "LastName is too long.");
                }
                if ((operatorInfo.Badge?.Length ?? 0) > 10)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied, "Badge is too long.");
                }
                //if ((operatorInfo.CardNumber?.Length ?? 0) > 25)
                //    throw new FriendlyException(FriendlyExceptionType.AccessDenied, "Card number is too long.");

                //----------------------------------------



                var badge = operatorInfo.Badge?.Trim().PadLeft(6, '0');
                debugStr = "Before getting Demo User for badge: " + badge;

                var user = await RestroomUnitOfWork.Get <User>().FirstOrDefaultAsync(m => m.Badge == badge);

                if (user == null)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessHasBeenRevoked, "", debugStr);
                }
                if (!user.Active)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, "", debugStr);
                }

                //var demoUser = await IsDemoUserAsync(operatorInfo.FirstName, operatorInfo.LastName, badge);
                var demoUser = user.IsDemo.GetValueOrDefault(false);

                debugStr = "After getting Demo User: "******"After getting Employee, DemoUser: {demoUser}, Found:{(employee != null)}";

                if (employee == null && !demoUser)
                {
                    var s = $"GetOperatorInfo. Employee not found." + $"debugStr: {debugStr}";
                    Logger.Write(s);
                    WriteLog(operatorInfo, s);
                    //await InvalidateOperatorAsync(badge);
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                }
                else if (employee != null && (
                             !string.Equals(employee.LastName, operatorInfo.LastName, StringComparison.OrdinalIgnoreCase) ||
                             //!string.Equals(employeeCardNumber, cardNumber, StringComparison.OrdinalIgnoreCase) ||

                             //!employee.SecurityCardEnabled.GetValueOrDefault(false) ||  // After the issue raise with one of the employees "Joseph Seibel", Michael decided to disabled this check
                             (!string.Equals(employee.FirstName, operatorInfo.FirstName, StringComparison.OrdinalIgnoreCase) &&
                              !string.Equals(employee.MiddleName, operatorInfo.FirstName, StringComparison.OrdinalIgnoreCase)))
                         )
                {
                    //var s =  $"GetOperatorInfo. Employee badge: {badge} found but names or card # {cardNumber} were not match.";
                    var s = $"GetOperatorInfo. Employee badge: {badge} found but names were not match.";
                    s += $"Entered: FirstName: {employee?.FirstName??""}, LastName: {employee?.LastName??""}";
                    Logger.Write(s);
                    WriteLog(operatorInfo, s);
                    //await InvalidateOperatorAsync(badge);
                    throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                }


                if (demoUser)
                {
                    CurrentUserName = "******";
                }
                else
                {
                    CurrentUserName = employee.Name;
                }


                var device = await RestroomUnitOfWork.Get <Device>()
                             .FirstOrDefaultAsync(m => m.DeviceGuid == operatorInfo.DeviceGuid);

                //User user = await RestroomUnitOfWork.Get<User>().FirstOrDefaultAsync(m => m.Badge == badge);

                //if (!string.Equals(user?.LastName, operatorInfo.LastName) ||
                //    (!string.Equals(user?.FirstName, operatorInfo.FirstName) &&
                //     !string.Equals(user?.MiddleName, operatorInfo.FirstName)))
                //    user = null;

                //debugStr = $"after getting device and user. DeviceGuid:{operatorInfo.DeviceGuid}, Badge: {badge}";

                if (!demoUser)
                {
                    if (operatorInfo.Validating && device == null)
                    {
                        throw new FriendlyException(FriendlyExceptionType.AccessDenied, "", debugStr);
                    }

                    if (device != null && !device.Active)
                    {
                        throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive,
                                                    $"debugStr: {debugStr}");
                    }
                }

                //if (user != null && !user.Active)
                //    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive,"", debugStr);


                if (operatorInfo.Validating && (device == null || !device.Active ||
                                                device.DeviceSessionId != operatorInfo.DeviceSessionId))
                {
                    if (device == null)
                    {
                        throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                    }
                    if (!device.Active)
                    {
                        throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive);
                    }
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedSessionMismatch);
                }

                if (operatorInfo.Validating && (user == null || !user.Active))
                {
                    throw new FriendlyException(user == null
                        ? FriendlyExceptionType.AccessHasBeenRevoked
                        : FriendlyExceptionType.AccessDeniedNotActive);
                }

                UserDevice userDevice = null;
                if (device != null)
                {
                    userDevice = await RestroomUnitOfWork.Get <UserDevice>()
                                 .FirstOrDefaultAsync(m => m.DeviceId == device.DeviceId && m.UserId == user.UserId);
                }
                if (device == null)
                {
                    device = new Device
                    {
                        Active      = true, //demoUser,
                        DeviceGuid  = operatorInfo.DeviceGuid,
                        DeviceModel = operatorInfo.DeviceModel,
                        DeviceOS    = operatorInfo.DeviceOS,
                        LastUsed    = DateTime.Now
                    };
                    device.DeviceSessionId = Guid.NewGuid().ToString(); //CreateDeviceSessionId(operatorInfo);
                }
                else
                {
                    //try
                    //{
                    if (operatorInfo.Validating && device.DeviceSessionId != operatorInfo.DeviceSessionId)
                    {
                        Logger.WriteError($"Badge:{badge}, Validating but sessions are not match!");
                        throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                    }

                    if (device.DeviceSessionId != operatorInfo.DeviceSessionId)
                    {
                        device.DeviceSessionId = Guid.NewGuid().ToString();
                    }

                    //var ticket = FormsAuthentication.Decrypt(device.DeviceSessionId);
                    //if (ticket == null || ticket.Name != operatorInfo.DeviceGuid)
                    //    throw new FriendlyException(FriendlyExceptionType.AccessDenied);

                    //if (ticket.Expired)
                    //    device.DeviceSessionId = CreateDeviceSessionId(operatorInfo);
                    //}
                    //catch (Exception ex)
                    //{
                    //    Logger.WriteError(ex.Message);
                    //    throw new FriendlyException(FriendlyExceptionType.AccessDenied);
                    //}
                }

                if (user == null)
                {
                    user = new User
                    {
                        Active = true,
                        Badge  = badge,
                    };
                }

                user.SecurityCardFormatted = employee?.SecurityCardFormatted;
                user.FirstName             = demoUser?"Demo":(employee?.FirstName ?? "");
                user.LastName   = demoUser?"User":(employee?.LastName ?? "");
                user.MiddleName = employee?.MiddleName ?? "";


                var confirmation = new Confirmation
                {
                    Badge            = badge,
                    Agreed           = operatorInfo.Agreed,
                    IncidentDateTime = operatorInfo.IncidentDateTime,
                    DeviceId         = operatorInfo.DeviceGuid,
                    Active           = true
                };


                device.LastUsed = DateTime.Now;

                user         = RestroomUnitOfWork.PrepUser(user);
                device       = RestroomUnitOfWork.PrepDevice(device);
                confirmation = RestroomUnitOfWork.PrepConfirmation(confirmation);
                await RestroomUnitOfWork.SaveChangesAsync();

                if (userDevice == null)
                {
                    userDevice        = new UserDevice();
                    userDevice.Active =
                        true; //demoUser || device.DeviceId==default(long) || (!string.IsNullOrWhiteSpace(operatorInfo.DeviceSessionId) && operatorInfo.DeviceSessionId == device.DeviceSessionId);
                }

                userDevice.LastLogon = DateTime.Now;
                userDevice.UserId    = user.UserId;
                userDevice.DeviceId  = device.DeviceId;

                userDevice = await RestroomUnitOfWork.SaveUserDeviceAsync(userDevice);



                operatorInfo.DeviceSessionId = device.DeviceSessionId;
                operatorInfo.SessionApproved = user.Active && userDevice.Active && device.Active;
            }
            catch (FriendlyException ex)
            {
                Logger.WriteError("debugStr:" + debugStr + ", Error:" + ex.Message);
                if (ex.ExceptionType != FriendlyExceptionType.AccessDeniedNotActive)
                {
                    throw;
                }
                operatorInfo.SessionApproved = false;
            }
            catch (DbEntityValidationException ex)
            {
                Logger.WriteError("DbEntityValidationException, debugStr:" + debugStr + ", Error:" + ex.Message);
                foreach (var eve in ex.EntityValidationErrors)
                {
                    Logger.WriteError($"Entity of type \"{eve.Entry.Entity.GetType().Name}\" in state \"{eve.Entry.State}\" has the following validation errors:");
                    foreach (var ve in eve.ValidationErrors)
                    {
                        Logger.WriteError($"- Property: \"{ve.PropertyName}\", Error: \"{ve.ErrorMessage}\"");
                    }
                }
                operatorInfo.SessionApproved = false;
            }
            catch (Exception ex)
            {
                Logger.WriteError("debugStr:" + debugStr + ", Error:" + ex.Message);
                operatorInfo.SessionApproved = false;
            }
            return(operatorInfo);
        }
        public async Task <AuthenticationViewModel> ValidateSecurityCode(AuthenticationViewModel authModel)
        {
            string debugStr = "";

            Logger.WriteDebug("ValidateSecurityCode called.");

            var jobTitle = "";

            try
            {
                authModel = SanitizeModel(authModel);


                User user = await RestroomUnitOfWork.Get <User>().FirstOrDefaultAsync(m => m.Badge == authModel.Badge);

                if (user == null || !user.Active)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $"user is not active.", debugStr);
                }

                var demoUser = user.IsDemo.GetValueOrDefault(false);
                //var demoUser = await IsDemoUserAsync(authModel.FirstName, authModel.LastName, authModel.Badge);
                //debugStr = "After getting Demo User: "******"", "");

                    authModel.SessionApproved = true;
                    authModel.DeviceSessionId = tempDevice.DeviceSessionId;
                    return(authModel);
                }

                var employee = await EmployeeRepository.GetEmployeeByBadgeAsync(authModel.Badge);

                debugStr = $"After getting Employee, Found:{(employee != null)}";

                if (employee == null)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $" User not found.", debugStr);
                }

                jobTitle = employee.JobTitle;


                var device = await RestroomUnitOfWork.Get <Device>().FirstOrDefaultAsync(m => m.DeviceGuid == authModel.DeviceGuid);

                debugStr = $"after getting device and user. DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}";

                if (device == null || !device.Active)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $" device is not Active.", debugStr);
                }



                debugStr = $"after getting device and user. DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}, UserId:{user.UserId}, DeviceId:{device.DeviceId}";

                UserDevice userDevice;
                userDevice = await RestroomUnitOfWork.Get <UserDevice>()
                             .FirstOrDefaultAsync(m => m.DeviceId == device.DeviceId && m.UserId == user.UserId);

                if (userDevice == null || !userDevice.Active)
                {
                    throw new FriendlyException(FriendlyExceptionType.AccessDeniedNotActive, $"userDevice is not active.", debugStr);
                }

                debugStr =
                    $"before checking 2Factor Auth. Client 2FACode:{authModel.Confirm2FACode},  DeviceGuid:{authModel.DeviceGuid}, Badge: {authModel.Badge}, UserId:{user.UserId}, DeviceId:{device.DeviceId}" +
                    $", 2FACode Expires:{device.Confirm2FAExpires?.ToString("yyyy-MM-dd HH:mm:ss")}";
                if (device.Confirm2FAExpires >= DateTime.Now && device.Confirm2FACode == authModel.Confirm2FACode)
                {
                    device.Confirmed2FACode = true;
                    device.DeviceSessionId  = Guid.NewGuid().ToString();
                }
                else
                {
                    throw new FriendlyException(FriendlyExceptionType.InvalidOrExpired2FAuth, $"Security Code is invalid or expired.", debugStr);
                }

                device = RestroomUnitOfWork.PrepDevice(device);
                await RestroomUnitOfWork.SaveChangesAsync();

                authModel.CanAddRestroom  = Config.JobTitlesAccessToAddRestroom.Any(m => m == jobTitle);
                authModel.CanEditRestroom = Config.JobTitlesAccessToEditRestroom.Any(m => m == jobTitle);

                authModel.DeviceSessionId = device.DeviceSessionId;
                authModel.SessionApproved = true;
            }
            catch (FriendlyException ex)
            {
                Logger.WriteError("debugStr:" + debugStr + ", Error:" + ex.Message);
                if (ex.ExceptionType != FriendlyExceptionType.AccessDeniedNotActive)
                {
                    throw;
                }
                authModel.SessionApproved = false;
            }
            catch (DbEntityValidationException ex)
            {
                Logger.WriteError("DbEntityValidationException, debugStr:" + debugStr + ", Error:" + ex.Message);
                foreach (var eve in ex.EntityValidationErrors)
                {
                    Logger.WriteError($"Entity of type \"{eve.Entry.Entity.GetType().Name}\" in state \"{eve.Entry.State}\" has the following validation errors:");
                    foreach (var ve in eve.ValidationErrors)
                    {
                        Logger.WriteError($"- Property: \"{ve.PropertyName}\", Error: \"{ve.ErrorMessage}\"");
                    }
                }
                authModel.SessionApproved = false;
            }
            catch (Exception ex)
            {
                Logger.WriteError("debugStr:" + debugStr + ", Error:" + ex.Message);
                authModel.SessionApproved = false;
            }

            return(authModel);
        }