using System.Collections.Generic;

using Hims.Shared.UserModels.Menu;

namespace Hims.Api.Controllers
{
    using System;
    using System.Linq;
    using System.Reflection;
    using System.Threading.Tasks;

    using Domain.Configurations;
    using Domain.Helpers;
    using Domain.Services;
    using Hims.Api.Models;
    using Hims.Infrastructure.Helpers;
    using Hims.Shared.UserModels.Common;
    using IdentityModel.Client;

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;

    using Models.Account;

    using Senders;

    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.Library;
    using Shared.Library.Enums;
    using Shared.UserModels.Filters;

    using Utilities;

    // ReSharper disable StyleCop.SA1126

    /// <inheritdoc />
    /// <summary>
    /// The account controller.
    /// </summary>
    [Route("api/account")]
    [Consumes("application/json")]
    [Produces("application/json")]
    public class AccountController : BaseController
    {
        /// <summary>
        /// The authentication helper.
        /// </summary>
        private readonly IAuthHelper authHelper;

        /// <summary>
        /// The account services.
        /// </summary>
        private readonly IAccountService accountServices;

        /// <summary>
        /// The account services.
        /// </summary>
        private readonly IPatientService patientServices;

        /// <summary>
        /// The account session services.
        /// </summary>
        private readonly IAccountSessionService accountSessionServices;

        /// <summary>
        /// The audit log services.
        /// </summary>
        private readonly IAuditLogService auditLogServices;

        /// <summary>
        /// The account credential services.
        /// </summary>
        private readonly IAccountCredentialService accountCredentialServices;

        /// <summary>
        /// The AES helper.
        /// </summary>
        private readonly IAESHelper aesHelper;

        /// <summary>
        /// The SMS sender.
        /// </summary>
        private readonly ISMSSender smsSender;

        /// <summary>
        /// The email sender.
        /// </summary>
        private readonly IEmailSender emailSender;

        /// <summary>
        /// The Application configuration.
        /// </summary>
        private readonly IApplicationConfiguration applicationConfiguration;

        /// <summary>
        /// The document helper.
        /// </summary>
        private readonly IDocumentHelper documentHelper;

        /// <summary>
        /// The ftp helper.
        /// </summary>
        private readonly IFtpHelper ftpHelper;

        /// <summary>
        /// The whats application SMS sender
        /// </summary>
        private readonly IWhatsAppSMSSender whatsAppSMSSender;

        /// <summary>
        /// The setting service
        /// </summary>
        private readonly ISettingService settingService;
        /// <inheritdoc />
        public AccountController(IAuthHelper authHelper, IAccountService accountServices, IAESHelper aesHelper, IAccountCredentialService accountCredentialServices, IAccountSessionService accountSessionServices, IAuditLogService auditLogServices, ISMSSender smsSender, IEmailSender emailSender, IApplicationConfiguration applicationConfiguration, IDocumentHelper documentHelper, IFtpHelper ftpHelper, IPatientService patientServices, IWhatsAppSMSSender whatsAppSMSSender, ISettingService settingService)
        {
            this.authHelper = authHelper;
            this.accountServices = accountServices;
            this.aesHelper = aesHelper;
            this.accountCredentialServices = accountCredentialServices;
            this.accountSessionServices = accountSessionServices;
            this.auditLogServices = auditLogServices;
            this.smsSender = smsSender;
            this.emailSender = emailSender;
            this.applicationConfiguration = applicationConfiguration;
            this.documentHelper = documentHelper;
            this.ftpHelper = ftpHelper;
            this.patientServices = patientServices;
            this.whatsAppSMSSender = whatsAppSMSSender;
            this.settingService = settingService;
        }

        #region Authentication

        /// <summary>
        /// To authenticate account.
        /// </summary>
        /// <param name="model">
        /// The login request model.
        /// </param>
        /// <returns>
        /// The account.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Login successful, login response model.
        /// - 400 - Invalid credentials.
        /// - 417 - Token generation failed.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("authenticate")]
        [ProducesResponseType(typeof(UserAccount), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> AuthenticateAsync([FromBody] LoginRequest model)
        {

            model = (LoginRequest)EmptyFilter.Handler(model);

            var identityServer = await this.authHelper.GetIdentityServerAsync();
            if (identityServer.IsError)
            {
                return this.ServerError(identityServer.Error);
            }

            var roles = await this.accountServices.GetAllRolesAsync();
            //roles.RemoveAt(roles.Single(m => m == (int)Roles.Patient));
            var authResponse = await this.authHelper.SignInAltAsync(identityServer, model.Username, model.Password, roles, null);
            if (authResponse.IsError)
            {
                var error = authResponse.ErrorDescription.ToEnum<UserAccountStatus>();
                try
                {
                    var accountInfo = await this.accountServices.GetAccountDetailAsync(model.Username, string.Join(",", model.AccountTypes.Select(m => (int)m)));
                    var description = $@"<b>{accountInfo.FullName}</b> ({accountInfo.RoleName}) <b>login failed</b> because ";

                    switch (error)
                    {
                        case UserAccountStatus.InactiveAccount:
                            description += " the account is Deactivated.";
                            break;
                        case UserAccountStatus.LockedAccount:
                            description += " the account was Locked.";
                            break;
                        case UserAccountStatus.InvalidPassword:
                            description += " of wrong Password.";
                            break;
                    }

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = accountInfo.AccountId,
                        LogTypeId = (int)LogTypes.LoginError,
                        LogFrom = (short)accountInfo.RoleId,
                        LogDate = DateTime.UtcNow,
                        LogDescription = description,
                        LocationId = model.LocationId
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception ex)
                {
                    //ignore
                }


                return this.GetUserAccountStatus(error);
            }

            if (string.IsNullOrEmpty(authResponse.AccessToken))
            {
                return this.Failed();
            }

            var accountClaims = await this.authHelper.FetchUserInfoAsync(identityServer, authResponse.AccessToken);
            if (accountClaims.IsError)
            {
                return this.ServerError();
            }

            var accountIdClaim = accountClaims.Claims.ToList().FirstOrDefault(x => x.Type == "sub")?.Value;
            if (string.IsNullOrEmpty(accountIdClaim))
            {
                return this.Failed();
            }

            var accountId = Convert.ToInt32(accountIdClaim);
            await this.accountServices.UpdateLastLoginDateAsync(accountId);
            return await this.GetUserAccountAsync(new AccountSessionModel { AccountId = accountId, DeviceToken = model.DeviceToken, DeviceId = model.DeviceId, DeviceType = (short)model.DeviceType }, authResponse, model.LocationId);

        }

        /// <summary>
        /// To get the access token based on refresh token.
        /// </summary>
        /// <param name="model">
        /// The refresh authentication request Model.
        /// </param>
        /// <returns>
        /// The Authentication token model.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Token successful and returns Authentication token object.
        /// - 400 - Locked account or Inactive account.
        /// - 417 - Token generation failed.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPut]
        [AllowAnonymous]
        [Route("refresh-authentication")]
        [ProducesResponseType(typeof(AuthToken), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> RefreshAuthenticationAsync([FromBody] RefreshAuthenticationRequest model)
        {
            try
            {
                model = (RefreshAuthenticationRequest)EmptyFilter.Handler(model);

                var identityServer = await this.authHelper.GetIdentityServerAsync();
                if (identityServer.IsError)
                {
                    return this.ServerError(identityServer.Error);
                }

                var response = await this.authHelper.RefreshSignInAsync(identityServer, model.Token);
                if (response.IsError)
                {
                    return this.ServerError(response.ErrorDescription);
                }

                if (string.IsNullOrEmpty(response.AccessToken))
                {
                    return this.Failed();
                }

                var authToken = new AuthToken
                {
                    Token = response.TokenType + " " + response.AccessToken,
                    ReferenceToken = response.RefreshToken,
                    Expires = DateTime.UtcNow.AddSeconds(response.ExpiresIn)
                };

                return this.Success(authToken);
            }
            catch (Exception e)
            {
                if (e.Message.Contains("Parameter is required (Parameter 'refresh_token')"))
                {
                    return this.ServerError("Session Expired.Please login again");
                }
                throw;
            }
        }
        #endregion


        #region Patient Authentication
        /// <summary>
        /// To patient authenticate account.
        /// </summary>
        /// <param name="model">
        /// The login request model.
        /// </param>
        /// <returns>
        /// The account.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Login successful, login response model.
        /// - 400 - Invalid credentials.
        /// - 417 - Token generation failed.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("patient-authenticate")]
        [ProducesResponseType(typeof(UserAccount), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> PatientAuthenticateAsync([FromBody] LoginRequest model)
        {
            model = (LoginRequest)EmptyFilter.Handler(model);

            var identityServer = await this.authHelper.GetIdentityServerAsync();
            if (identityServer.IsError)
            {
                return this.ServerError(identityServer.Error);
            }

            var roles = await this.accountServices.GetPatientRolesAsync();
            if (model.PatientId != null)
            {
                var patientData = await this.patientServices.FindAsync((int)model.PatientId);
                model.Username = "1:" + patientData.Mobile;
            }
            var authResponse = await this.authHelper.PatientSignInAsync(identityServer, model.Username, model.Password, model.AccountId);
            if (authResponse.IsError)
            {
                var error = authResponse.ErrorDescription.ToEnum<UserAccountStatus>();
                try
                {
                    var accountInfo = await this.accountServices.GetAccountDetailAsync(model.Username, string.Join(",", model.AccountTypes.Select(m => (int)m)));
                    var description = $@"<b>{accountInfo.FullName}</b> ({accountInfo.RoleName}) <b>login failed</b> because ";

                    switch (error)
                    {
                        case UserAccountStatus.InactiveAccount:
                            description += " the account is Deactivated.";
                            break;
                        case UserAccountStatus.LockedAccount:
                            description += " the account was Locked.";
                            break;
                        case UserAccountStatus.InvalidPassword:
                            description += " of wrong Password.";
                            break;
                        case UserAccountStatus.InvalidAccount:
                            description += " the account does not exist password.";
                            break;
                    }

                    var auditLogModel = new AuditLogModel
                    {
                        AccountId = accountInfo.AccountId,
                        LogTypeId = (int)LogTypes.LoginError,
                        LogFrom = (short)accountInfo.RoleId,
                        LogDate = DateTime.UtcNow,
                        LogDescription = description,
                        LocationId = model.LocationId
                    };
                    await this.auditLogServices.LogAsync(auditLogModel);
                }
                catch (Exception ex)
                {
                    //ignore
                }


                return this.GetUserAccountStatus(error);
            }
            if (string.IsNullOrEmpty(authResponse.AccessToken))
            {
                return this.Failed();
            }

            var accountClaims = await this.authHelper.FetchUserInfoAsync(identityServer, authResponse.AccessToken);
            if (accountClaims.IsError)
            {
                return this.ServerError();
            }

            var accountIdClaim = accountClaims.Claims.ToList().FirstOrDefault(x => x.Type == "sub")?.Value;
            if (string.IsNullOrEmpty(accountIdClaim))
            {
                return this.Failed();
            }

            var accountId = Convert.ToInt32(accountIdClaim);
            await this.accountServices.UpdateLastLoginDateAsync(accountId);
            return await this.GetUserAccountAsync(new AccountSessionModel { AccountId = accountId, DeviceToken = model.DeviceToken, DeviceId = model.DeviceId, DeviceType = (short)model.DeviceType }, authResponse, model.LocationId);

        }


        #endregion

        #region OTP

        /// <summary>
        /// To send OTP to email/mobile.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The OTP <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - OTP send to email/mobile successful.
        /// - 400 - Invalid email/mobile.
        /// - 500 - Problem with Email/SMS server or server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("send-otp")]
        [ProducesResponseType(typeof(OTPResponse), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SendOTPAsync([FromBody] LoginOTPRequest model)
        {
            model = (LoginOTPRequest)EmptyFilter.Handler(model);

            UserAccountStatus accountStatus;
            AccountModel account;
            OTPResponse response;

            if ((model.CountryId == null || model.CountryId == 0) && model.Username.Contains("@"))
            {
                (accountStatus, account) = await this.accountServices.ValidateAsync(model.Username, model.AccountTypes);
                if (accountStatus != UserAccountStatus.Success)
                {
                    return this.GetUserAccountStatus(accountStatus);
                }

                response = await this.emailSender.SendOTPAsync(account.Email, account.FullName);
            }

            else
            {

                (accountStatus, account) = await this.accountServices.ValidateAsync(model.Username, Convert.ToInt32(model.CountryId), model.AccountTypes);
                if (accountStatus != UserAccountStatus.Success)
                {
                    return this.GetUserAccountStatus(accountStatus);
                }
                var otp = CoreFilter.RandomNumbers(4);
                var WhatsAppMessageSetting = await this.settingService.FetchAsync("WhatsAppMsgService", null, null);
                var WhatsAppMessage = WhatsAppMessageSetting.ToList();
                if ((bool)WhatsAppMessage[0].Active)
                {
                    bool Ret = await this.whatsAppSMSSender.SendOTPAsync(account.Mobile, otp);
                }
                response = await this.smsSender.SendOTPAsync(account.Mobile, account.CountryId,otp);
            }

            response.AccountId = account.AccountId;
            return this.Success(response);
        }
        /// <summary>
        /// To send OTP to email/mobile.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The OTP <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - OTP send to email/mobile successful.
        /// - 400 - Invalid email/mobile.
        /// - 500 - Problem with Email/SMS server or server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("send-otp-patient")]
        [ProducesResponseType(typeof(OTPResponse), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SendOTPPatientAsync([FromBody] LoginOTPRequest model)
        {
            model = (LoginOTPRequest)EmptyFilter.Handler(model);

            UserAccountStatus accountStatus;
            AccountModel account;
            OTPResponse response;

            if ((model.CountryId == null || model.CountryId == 0) && model.Username.Contains("@"))
            {
                (accountStatus, account) = await this.accountServices.ValidatePatientAsync(model.Username, model.AccountTypes, model.AccountId);
                if (accountStatus != UserAccountStatus.Success)
                {
                    return this.GetUserAccountStatus(accountStatus);
                }

                response = await this.emailSender.SendOTPAsync(account.Email, account.FullName);
            }
            else
            {
                if (model.PatientId != null)
                {
                    var patientData = await this.patientServices.FindAsync((int)model.PatientId);
                    model.Username = patientData.Mobile;
                }
                (accountStatus, account) = await this.accountServices.ValidatePatientAsync(model.Username, Convert.ToInt32(model.CountryId), model.AccountTypes, model.AccountId);
                if (accountStatus != UserAccountStatus.Success)
                {
                    return this.GetUserAccountStatus(accountStatus);
                }
                var otp = CoreFilter.RandomNumbers(4);
                var WhatsAppMessageSetting = await this.settingService.FetchAsync("WhatsAppMsgService", null, null);
                var WhatsAppMessage = WhatsAppMessageSetting.ToList();
                if ((bool)WhatsAppMessage[0].Active)
                {
                    bool Ret = await this.whatsAppSMSSender.SendOTPAsync(account.Mobile, otp);
                }
                response = await this.smsSender.SendOTPAsync(account.Mobile, account.CountryId,otp);
            }

            response.AccountId = account.AccountId;
            return this.Success(response);
        }
        /// <summary>
        /// To verify email OTP.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The OTP <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - OTP verified.
        /// - 400 - Invalid mobile number.
        /// - 417 - Token generation failed.
        /// - 500 - Problem with server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("verify-otp")]
        [ProducesResponseType(typeof(UserAccount), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> VerifyOTPAsync([FromBody] VerifyOTPRequest model)
        {
            model = (VerifyOTPRequest)EmptyFilter.Handler(model);

            var identityServer = await this.authHelper.GetIdentityServerAsync();
            if (identityServer.IsError)
            {
                return this.ServerError(identityServer.Error);
            }

            var authResponse = await this.authHelper.SignInAsync(identityServer, string.Empty, string.Empty, model.AccountTypes, model.AccountId);
            if (authResponse.IsError)
            {
                return this.ServerError(authResponse.ErrorDescription);
            }

            if (string.IsNullOrEmpty(authResponse.AccessToken))
            {
                return this.Failed();
            }

            return await this.GetUserAccountAsync(new AccountSessionModel { AccountId = model.AccountId, DeviceToken = model.DeviceToken, DeviceId = model.DeviceId, DeviceType = (short)model.DeviceType }, authResponse, 0);
        }

        #endregion

        #region Forgot Password

        /// <summary>
        /// To forgot password
        /// </summary>
        /// <param name="model">
        /// The password Model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Reset password link sent to mail.
        /// - 400 - Invalid email.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(typeof(OTPResponse), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        [Route("forgot-password")]
        public async Task<ActionResult> ForgotPasswordAsync([FromBody] ForgotPasswordRequest model)
        {
            model = (ForgotPasswordRequest)EmptyFilter.Handler(model);

            if (!model.Username.Contains("@"))
            {
                string mobile;
                int countryId;
                try
                {
                    mobile = model.Username.Split(":")[1];
                    countryId = Convert.ToInt32(model.Username.Split(":")[0]);
                }
                catch
                {
                    return this.BadRequest();
                }

                if (string.IsNullOrEmpty(model.Password))
                {
                    var (accountStatus, account) = await this.accountServices.ValidateAsync(mobile, countryId, model.AccountTypes);
                    if (accountStatus != UserAccountStatus.Success)
                    {
                        return this.GetUserAccountStatus(accountStatus);
                    }
                    var otp = CoreFilter.RandomNumbers(4);
                    var WhatsAppMessageSetting = await this.settingService.FetchAsync("WhatsAppMsgService", null, null);
                    var WhatsAppMessage = WhatsAppMessageSetting.ToList();
                    if ((bool)WhatsAppMessage[0].Active)
                    {
                        bool Ret = await this.whatsAppSMSSender.SendOTPAsync(mobile, otp);
                    }
                    var otpResponse = await this.smsSender.SendOTPAsync(mobile, countryId,otp);
                    otpResponse.AccountId = account.AccountId;
                    otpResponse.FullName = account.FullName;

                    return this.Success(otpResponse);
                }
            }
            else
            {
                var email = model.Username;
                if (string.IsNullOrEmpty(email))
                {
                    return this.BadRequest();
                }

                if (string.IsNullOrEmpty(model.Password))
                {
                    var (accountStatus, account) = await this.accountServices.ValidateAsync(model.Username, model.AccountTypes);
                    if (accountStatus != UserAccountStatus.Success)
                    {
                        return this.GetUserAccountStatus(accountStatus);
                    }

                    var otpResponse = await this.emailSender.SendOTPAsync(email, account.FullName);
                    otpResponse.AccountId = account.AccountId;
                    otpResponse.FullName = account.FullName;

                    return this.Success(otpResponse);
                }
            }

            var response = await this.accountCredentialServices.CreateAsync(model.AccountId, model.Password);
            return response <= 0 ? this.ServerError() : this.Success("Password updated successfully.");
        }

        /// <summary>
        /// To reset password
        /// </summary>
        /// <param name="model">
        /// The password Model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Reset password link sent to mail.
        /// - 400 - Invalid email.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        [Route("reset-password")]
        public async Task<ActionResult> ResetPasswordAsync([FromBody] ForgotPasswordRequest model)
        {
            model = (ForgotPasswordRequest)EmptyFilter.Handler(model);

            // Mail reset Password
            if (!string.IsNullOrEmpty(model.Username))
            {
                var (accountStatus, account) = await this.accountServices.ValidateAsync(model.Username, model.AccountTypes);
                if (accountStatus != UserAccountStatus.Success)
                {
                    return this.GetUserAccountStatus(accountStatus);
                }

                var resetPasswordLink = this.applicationConfiguration.ResetPasswordLink + this.aesHelper.Encode(account.AccountId.ToString() + '.' + DateTime.Now.ToString("yyyy-MM-dd hh:mm tt"));
                var accountType = Enum.GetName(typeof(AccountType), account.RoleId);

                // var smsResponse = await this.smsSender.SendResetPasswordAsync(mobile, account.FullName, accountType, resetPasswordLink, countryId);
                // if (!smsResponse)
                // {
                //    return this.Success(this.SMSServerError());
                // }
                var emailResponse = await this.emailSender.ResetPasswordMailAsync(account.Email, account.FullName, accountType, resetPasswordLink);
                if (!emailResponse)
                {
                    this.Success(this.MailServerError());
                }

                var auditLogModel = new AuditLogModel
                {
                    AccountId = account.AccountId,
                    LogTypeId = (int)LogTypes.Accounts,
                    LogFrom = (short)account.RoleId,
                    LogDate = DateTime.UtcNow,
                    LogDescription = $"Reset password link has been sent to {account.Email} email address."
                };
                await this.auditLogServices.LogAsync(auditLogModel);

                return this.Success("Reset password link has been sent to your registered email address successfully.");
            }

            return this.NotFound();
        }

        /// <summary>
        /// To change account's password.
        /// </summary>
        /// <param name="model">
        /// The change password request Model.
        /// </param>
        /// <returns>
        /// The HTTP status.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Account's password has been successfully updated.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPut]
        [AllowAnonymous]
        [Route("change-password")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ChangePasswordAsync([FromBody] ChangePasswordRequest model)
        {
            model = (ChangePasswordRequest)EmptyFilter.Handler(model);

            var created = await this.accountCredentialServices.CreateAsync(model.AccountId, model.Password);
            if (created <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(model.AccountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} ({account.RoleName}) account's password has been updated successfully.",
                LocationId=model.LocationId
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account's password has been updated successfully.");
        }


        /// <summary>
        /// To change account's password.
        /// </summary>
        /// <param name="model">
        /// The change password request Model.
        /// </param>
        /// <returns>
        /// The HTTP status.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Account's password has been successfully updated.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPut]
        [AllowAnonymous]
        [Route("patient-change-password")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> PatientChangePasswordAsync([FromBody] ChangePasswordRequest model)
        {
            model = (ChangePasswordRequest)EmptyFilter.Handler(model);

            var created = await this.accountCredentialServices.PatientPasswordCreateAsync(model.UserName, model.RoleId, model.Password);
            if (created <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(model.AccountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} ({account.RoleName}) account's password has been updated successfully."
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account's password has been updated successfully.");
        }


        /// <summary>
        /// To forgot password
        /// </summary>
        /// <param name="model">
        /// The password Model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Reset password link sent to mail.
        /// - 400 - Invalid email.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(typeof(OTPResponse), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        [Route("patient-forgot-password")]
        public async Task<ActionResult> PatientForgotPasswordAsync([FromBody] ForgotPasswordRequest model)
        {
            model = (ForgotPasswordRequest)EmptyFilter.Handler(model);
            var response = 0;
            if (!model.Username.Contains("@"))
            {
                string mobile;
                int countryId;
                try
                {
                    mobile = model.Username.Split(":")[1];
                    countryId = Convert.ToInt32(model.Username.Split(":")[0]);
                }
                catch
                {
                    return this.BadRequest();
                }

                if (string.IsNullOrEmpty(model.Password))
                {
                    var (accountStatus, account) = await this.accountServices.ValidateAsync(mobile, countryId, model.AccountTypes);
                    if (accountStatus != UserAccountStatus.Success)
                    {
                        return this.GetUserAccountStatus(accountStatus);
                    }
                    var otp = CoreFilter.RandomNumbers(4);
                    var WhatsAppMessageSetting = await this.settingService.FetchAsync("WhatsAppMsgService", null, null);
                    var WhatsAppMessage = WhatsAppMessageSetting.ToList();
                    if ((bool)WhatsAppMessage[0].Active)
                    {
                        bool Ret = await this.whatsAppSMSSender.SendOTPAsync(mobile, otp);
                    }
                    var otpResponse = await this.smsSender.SendOTPAsync(mobile, countryId,otp);
                    otpResponse.AccountId = account.AccountId;
                    otpResponse.FullName = account.FullName;

                    return this.Success(otpResponse);
                }
            }
            else
            {
                var email = model.Username;
                if (string.IsNullOrEmpty(email))
                {
                    return this.BadRequest();
                }

                if (string.IsNullOrEmpty(model.Password))
                {
                    var (accountStatus, account) = await this.accountServices.ValidateAsync(model.Username, model.AccountTypes);
                    if (accountStatus != UserAccountStatus.Success)
                    {
                        return this.GetUserAccountStatus(accountStatus);
                    }

                    var otpResponse = await this.emailSender.SendOTPAsync(email, account.FullName);
                    otpResponse.AccountId = account.AccountId;
                    otpResponse.FullName = account.FullName;

                    return this.Success(otpResponse);
                }
            }
            if (!model.Username.Contains("@"))
            {
                response = await this.accountCredentialServices.PatientPasswordCreateAsync(model.Username.Split(":")[1], model.RoleId, model.Password);
            }
            else
            {
                response = await this.accountCredentialServices.PatientPasswordCreateAsync(model.Username, model.RoleId, model.Password);
            }
            return response <= 0 ? this.ServerError() : this.Success("Password updated successfully.");
        }
        /// <summary>
        /// To change account's password.
        /// </summary>
        /// <param name="model">
        /// The change password request Model.
        /// </param>
        /// <returns>
        /// The HTTP status.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Account's password has been successfully updated.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPut]
        [AllowAnonymous]
        [Route("create-password")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> CreatePasswordAsync([FromBody] LoginRequest model)
        {
            model = (LoginRequest)EmptyFilter.Handler(model);
            var accountId = 0;
            if (!string.IsNullOrEmpty(model.EncryptedAccountId))
            {
                accountId = Convert.ToInt32(this.aesHelper.Decode(model.EncryptedAccountId));
            }

            var created = await this.accountCredentialServices.CreatePasswordAsync(accountId, model.Password);
            if (created <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(accountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} ({account.RoleName}) account password has been created successfully."
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            var response = await this.AuthenticateAsync(model);
            return this.Success(response);
        }

        #endregion

        /// <summary>
        /// To update agreement status of an account.
        /// </summary>
        /// <param name="model">
        /// The agreement status request Model.
        /// </param>
        /// <returns>
        /// The HTTP status.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Agreement status has been successfully updated.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPut]
        [Authorize]
        [Route("update-agreement-status")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> UpdateAgreementStatusAsync([FromBody] AgreementStatusRequest model)
        {
            model = (AgreementStatusRequest)EmptyFilter.Handler(model);

            var agreed = await this.accountServices.UpdateAgreementStatusAsync(model.AccountId);
            if (agreed <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(model.AccountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} ({account.RoleName}) agreement has been agreed successfully.",
                LocationId = null
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account's agreement has been agreed successfully.");
        }

        /// <summary>
        /// To logout from application.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Logged out successfully.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("logout")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> LogoutAsync([FromBody] LogoutRequest model, [FromHeader] LocationHeader header)
        {
            model = (LogoutRequest)EmptyFilter.Handler(model);

            var account = await this.accountServices.FindAsync(model.AccountId);

            // await this.accountSessionServices.DeleteAsync(model.AccountId, model.DeviceType, model.DeviceId);
            await this.accountSessionServices.DeleteAsync(model.AccountId, model.DeviceId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = model.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,

                LogDescription = $"<b>{account.FullName}</br> ({account.RoleName}) has been logged out from {account.LocationName} Branch.",
                LocationId = Convert.ToInt32(header.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account has been logged out.");
        }

        /// <summary>
        /// To logout from application.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Logged out successfully.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("get-menus")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> GetMenuAsync([FromBody] MenuRequest model)
        {
            var data = new OverAllModel { Menus = new List<Shared.UserModels.Menu.ViewModel>(), IsFullAccess = false };
            try
            {
                var menuAccess = await this.accountServices.IsMenuFullAccessAsync(model.RoleId);
                data.IsFullAccess = menuAccess.IsFullAccess;

                var defaultMenu = menuAccess.InitialRouteMenuId != null
                    ? await this.accountServices.GetDefaultMenuAsync(menuAccess.InitialRouteMenuId)
                    : null;

                var menus = await this.accountServices.FetchMenuAsync(model.AccountId, menuAccess.IsFullAccess);
                var menuButtonCodes = await this.accountServices.GetMenuButtonCodesAsync(model.RoleId);
                data.MenuButtonCodes = menuButtonCodes.ToList();
                var menusList = menus.ToList();
                var withOutDefault = menusList;

                if (defaultMenu != null)
                {
                    withOutDefault = menusList.Where(x => x.Url != defaultMenu.Url).ToList();
                }

                data.Menus = defaultMenu != null
                    ? new List<Shared.UserModels.Menu.ViewModel> { defaultMenu }
                    : new List<Shared.UserModels.Menu.ViewModel>();

                data.Menus.AddRange(withOutDefault);

                return this.Ok(data);
            }
            catch (Exception ex)
            {
                return this.Ok(data);
            }
        }

        /// <summary>
        /// To logout from application.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Logged out successfully.
        /// - 500 - Problem with Server side code.
        /// </returns>
        [HttpPost]
        [AllowAnonymous]
        [Route("web-logout")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> WebLogoutAsync([FromBody] LogoutRequest model, [FromHeader] LocationHeader header)
        {
            model = (LogoutRequest)EmptyFilter.Handler(model);

            var account = await this.accountServices.FindAsync(model.AccountId);

            await this.accountSessionServices.WebLogoutAsync(model.AccountId, model.DeviceType);

            var auditLogModel = new AuditLogModel
            {
                AccountId = model.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"<b>{account.FullName}</b> has been logged out.",
                LocationId = Convert.ToInt32(header.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account has been logged out.");
        }

        /// <summary>
        /// To logout from application.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - Logged out successfully.
        /// - 500 - Problem with Server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("logout-alt")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> LogoutAltAsync([FromBody] LogoutRequest model, [FromHeader] LocationHeader header)
        {
            model = (LogoutRequest)EmptyFilter.Handler(model);

            var account = await this.accountServices.FindAsync(model.AccountId);
            await this.accountSessionServices.DeleteAsync(model.AccountId, model.DeviceId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = model.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"<b>{account.FullName}</b> ({account.RoleName}) has been logged out.",
                LocationId = Convert.ToInt32(header.LocationId)
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success("Account has been logged out.");
        }

        /// <summary>
        /// To send OTP to email/mobile.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The OTP <see cref="Task"/>.
        /// </returns>
        /// <remarks>
        /// ### REMARKS ###
        /// The following codes are returned
        /// - 200 - OTP send to email/mobile successful.
        /// - 400 - Invalid email/mobile.
        /// - 500 - Problem with Email/SMS server or server side code.
        /// </remarks>
        [HttpPost]
        [AllowAnonymous]
        [Route("send-app-link")]
        [ProducesResponseType(typeof(OTPResponse), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> SendAppLinkAsync([FromBody] LoginOTPRequest model)
        {
            model = (LoginOTPRequest)EmptyFilter.Handler(model);

            var response = await this.emailSender.SendAppLinksAsync(model.Username);
            return this.Success(response);
        }

        #region UserAccounts

        /// <summary>
        /// The fetch async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("fetch")]
        [ProducesResponseType(typeof(AccountModel), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FetchAsync([FromBody] UserFilterModel model)
        {
            model = (UserFilterModel)EmptyFilter.Handler(model);

            var userAccounts = await this.accountServices.FetchAsync(model);

            return this.Success(userAccounts);
        }

        /// <summary>
        /// The find async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("find")]
        [ProducesResponseType(typeof(AccountModel), 200)]
        [ProducesResponseType(400)]
        [ProducesResponseType(417)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindAsync([FromBody] UserFilterModel model)
        {
            model = (UserFilterModel)EmptyFilter.Handler(model);

            var userAccounts = await this.accountServices.FindUserAsync(model.UserId);

            return this.Success(userAccounts);
        }

        /// <summary>
        /// The modify status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [Authorize]
        [Route("modify-status")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> ModifyStatusAsync([FromBody] AccountModel model)
        {
            model = (AccountModel)EmptyFilter.Handler(model);

            var agreed = await this.accountServices.ModifyStatusAsync(model.AccountId, Convert.ToInt32(model.ModifiedBy), model.Active);
            if (agreed <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(model.AccountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} account has been {(model.Active ? "Activated" : "Deactivated")} successfully."
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success($"{account.FullName} account has been {(model.Active ? "Activated" : "Deactivated")} successfully.");
        }

        /// <summary>
        /// The locked status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [Authorize]
        [Route("modify-locked-status")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> LockedStatusAsync([FromBody] AccountModel model)
        {
            model = (AccountModel)EmptyFilter.Handler(model);

            var agreed = await this.accountServices.LockedStatusAsync(model.AccountId, Convert.ToInt32(model.ModifiedBy), model.IsLocked);
            if (agreed <= 0)
            {
                return this.ServerError();
            }

            var account = await this.accountServices.FindAsync(model.AccountId);
            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"{account.FullName} account has been {(model.IsLocked ? "Locked" : "Unlocked")} successfully."
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            return this.Success($"{account.FullName} account has been {(model.IsLocked ? "Locked" : "Unlocked")} successfully.");
        }

        /// <summary>
        /// The locked status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [AllowAnonymous]
        [Route("check-user")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindUserAsync([FromBody] LoginRequest model)
        {
            model = (LoginRequest)EmptyFilter.Handler(model);

            var accountInfo = await this.accountServices.GetAccountDetailAsync(model.Username, string.Join(",", model.AccountTypes.Select(m => (int)m)));

            return this.Success(new { EncryptedAccountId = accountInfo != null ? this.aesHelper.Encode(accountInfo.AccountId.ToString()) : null, ManualVerified = accountInfo != null ? accountInfo.ManualVerified : null, PasswordExist = accountInfo != null ? accountInfo.PasswordExist : null });
        }

        /// <summary>
        /// The locked status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPut]
        [AllowAnonymous]
        [Route("check-user-list")]
        [ProducesResponseType(typeof(string), 200)]
        [ProducesResponseType(500)]
        public async Task<ActionResult> FindUserListAsync([FromBody] LoginRequest model)
        {
            model = (LoginRequest)EmptyFilter.Handler(model);

            var accountInfo = await this.accountServices.GetAccountDetailListAsync(model.Mobile, string.Join(",", model.AccountTypes.Select(m => (int)m)), model.Username);

            return this.Success(accountInfo);
        }

        /// <summary>
        /// The locked status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Route("is-nurse")]
        public async Task<ActionResult> GetIsNurseAsync([FromBody] IdRequest model)
        {
            var results = await this.accountServices.GetIsNurse(model);
            return this.Success(results);
        }

        /// <summary>
        /// Modifies the account location asynchronous.
        /// </summary>
        /// <param name="model">The model.</param>
        /// <returns></returns>
        [HttpPost]
        [Authorize]
        [Route("modify-account-location")]
        public async Task<ActionResult> ModifyAccountLocationAsync([FromBody] AccountLocationModel model)
        {
            model = (AccountLocationModel)EmptyFilter.Handler(model);
            var response = await this.accountServices.ModifyAccountsLocation(model.LocationIds, model.AccountId);
            return response > 0 ? this.Success("User location updated successfully") : this.BadRequest("Unable to update location.");
        }

        #endregion

        /// <summary>
        /// Gets the user account asynchronous.
        /// </summary>
        /// <param name="accountSession">The account session.</param>
        /// <param name="authToken">The authentication token.</param>
        /// <param name="locationId">The location identifier.</param>
        /// <returns></returns>
        [NonAction]
        private async Task<ObjectResult> GetUserAccountAsync(AccountSessionModel accountSession, TokenResponse authToken, int locationId)
        {
            var account = locationId != 0
                ? await this.accountServices.FindByLocationIdAsync(accountSession.AccountId, locationId)
                : await this.accountServices.FindAsync(accountSession.AccountId);

            if (account == null || account.AccountId == 0)
            {
                return this.BadRequest("Sorry! We don't have a user in the system.");
            }

            if (string.IsNullOrEmpty(accountSession.DeviceToken) || string.IsNullOrEmpty(accountSession.DeviceId))
            {
                account.SessionId = null;
            }
            else
            {
                // Create Account Session
                var accountSessionId = await this.accountSessionServices.CreateAsync(new AccountSessionModel
                {
                    AccountId = accountSession.AccountId,
                    DeviceType = accountSession.DeviceType,
                    DeviceToken = accountSession.DeviceToken,
                    DeviceId = accountSession.DeviceId,
                    Description = string.Empty
                });

                if (accountSessionId <= 0)
                {
                    return this.ServerError();
                }

                account.SessionId = accountSessionId;
            }

            account.Token = authToken.TokenType + " " + authToken.AccessToken;
            account.ReferenceToken = authToken.RefreshToken;
            account.AllowVideoCall = this.applicationConfiguration.AllowVideoCall;
            account.Expires = DateTime.UtcNow.AddSeconds(authToken.ExpiresIn);

            //if(!string.IsNullOrEmpty(account.ThumbnailUrl) && account.ThumbnailUrl.StartsWith("ftp"))
            //{
            //    account.ThumbnailUrl = await this.documentHelper.FetchImageBase64(account.AccountId, account.ThumbnailUrl);
            //}
            //else
            //{
            //    account.ThumbnailUrl = null;
            //}
            //if (!string.IsNullOrEmpty(account.ThumbnailUrl))
            //{
            //    string url = this.ftpHelper.GetFtpUrl("PatientProfile");
            //    string ftpfullpath = url + account.ReferenceId + "/" + account.ThumbnailUrl;
            //    account.ThumbnailUrl = await this.ftpHelper.FetchImageBase64(account.ReferenceId, ftpfullpath);
            //}
            await this.accountServices.UpdateLoginSuccessfulAsync(account.AccountId);

            var auditLogModel = new AuditLogModel
            {
                AccountId = account.AccountId,
                LogTypeId = (int)LogTypes.Accounts,
                LogFrom = (short)account.RoleId,
                LogDate = DateTime.UtcNow,
                LogDescription = $"<b>{account.FullName}</b> ({account.RoleName}) has been logged in to {account.LocationName} Branch.",
                LocationId = account.LocationId
            };
            await this.auditLogServices.LogAsync(auditLogModel);

            account.EncryptedReferenceId = this.aesHelper.Encode(account.ReferenceId.ToString());
            return this.Success(account);
        }

        /// <summary>
        /// The get user account status.
        /// </summary>
        /// <param name="accountStatus">
        /// The account status.
        /// </param>
        /// <returns>
        /// The <see cref="ObjectResult"/>.
        /// </returns>
        [NonAction]
        private ObjectResult GetUserAccountStatus(UserAccountStatus accountStatus)
        {
            switch (accountStatus)
            {
                case UserAccountStatus.InvalidAccount:
                    return this.BadRequest("Sorry! We don't have a user in the system.");
                case UserAccountStatus.InactiveAccount:
                    return this.BadRequest("Oh no! You're in inactive status. Please try again or contact an administrator.");
                case UserAccountStatus.LockedAccount:
                    return this.BadRequest("Oh no! Your account has been locked. Please contact an administrator.");
                case UserAccountStatus.InvalidPassword:
                    return this.BadRequest("Oh no! You have given invalid Password.");
                default:
                    return this.ServerError();
            }
        }

        /// <summary>
        /// The locked status async.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        [HttpPost]
        [Authorize]
        [Route("check-caller")]
        [ProducesResponseType(typeof(IEnumerable<PatientModel>), 200)]
        [ProducesResponseType(500)]

        public async Task<ActionResult> CheckCallerDetailsAsync([FromBody] IdRequest model)
        {
            model = (IdRequest)EmptyFilter.Handler(model);
            var patients = await this.accountServices.FetchCallerUserDetailsAsync(model);
            if (patients == null)
            {
                return this.Conflict("Caller Details not found");
            }
            foreach (var patient in patients.OrderBy(m => m.PatientId))
            {
                patient.EncryptedPatientId = this.aesHelper.Encode(patient.PatientId.ToString());
            }
            return this.Success(patients);
        }
    }
}