namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    using Dapper;

    using Domain.Configurations;
    using Domain.Helpers;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;

    using Shared.EntityModels;
    using Shared.Library;
    using Shared.Library.Enums;

    using Hims.Domain.Entities;
    using Hims.Shared.UserModels.Filters;
    using Menu = Hims.Shared.UserModels.Menu;
    using System.Collections;
    using Hims.Shared.UserModels.Common;

    /// <inheritdoc />
    public class AccountServices : IAccountService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// The SHA helper.
        /// </summary>
        private readonly IShaHelper shaHelper;

        /// <summary>
        /// The amazon s 3 configuration.
        /// </summary>
        private readonly IAmazonS3Configuration amazonS3Configuration;

        /// <summary>
        /// The running environment.
        /// </summary>
        private readonly IRunningEnvironment runningEnvironment;

        /// <inheritdoc cref="IAmazonS3Configuration"/> />
        public AccountServices(IUnitOfWork unitOfWork, IShaHelper shaHelper, IAmazonS3Configuration amazonS3Configuration, IRunningEnvironment runningEnvironment)
        {
            this.shaHelper = shaHelper;
            this.amazonS3Configuration = amazonS3Configuration;
            this.unitOfWork = unitOfWork;
            this.runningEnvironment = runningEnvironment;
        }

        /// <inheritdoc />
        public async Task<Tuple<UserAccountStatus, int>> ValidateAsync(string userName, string password)
        {
            string query;
            bool inusername = userName.Contains(":");
            if (inusername)
            {
                if (userName.Contains("!!"))
                {
                    var mobile = userName.Split(":")[1].Split("!!")[0];
                    var accountId = userName.Split(":")[1].Split("!!")[1];
                    var countryId = userName.Split(":")[0];
                    query = $@"SELECT act.""AccountId"", act.""RoleId"", act.""Email"", act.""Mobile"", act.""CountryId"",
                        CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
                        CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
                        act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
                        LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
                        --LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
                        LEFT JOIN ""ProviderAvailability"" PAY ON PAY.""ProviderAvailabilityId"" = U.""ProviderAvailabilityId""
                        LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PAY.""ProviderId""
                        WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}' AND act.""AccountId""= {accountId}";
                }
                else
                {
                    var mobile = userName.Split(":")[1];
                    var countryId = userName.Split(":")[0];
                    query = $@"SELECT act.""AccountId"", act.""RoleId"", act.""Email"", act.""Mobile"", act.""CountryId"",
                        CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
                        CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
                        act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
                        LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
                        --LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
                        LEFT JOIN ""ProviderAvailability"" PAY ON PAY.""ProviderAvailabilityId"" = U.""ProviderAvailabilityId""
                        LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PAY.""ProviderId""
                        WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}'";
                }
            }
            else
            {
                if (userName.Contains("@"))
                {
                    query = $@"SELECT act.""AccountId"", act.""RoleId"", act.""Email"", act.""Mobile"", act.""CountryId"",
                        CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
                        CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
                        act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
                        LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
                        --LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
                        LEFT JOIN ""ProviderAvailability"" PAY ON PAY.""ProviderAvailabilityId"" = U.""ProviderAvailabilityId""
                        LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PAY.""ProviderId""
                        WHERE UPPER(act.""Email"") = '{userName.Trim().ToUpper()}'";
                }
                else
                {
                    query = $@"SELECT act.""AccountId"", act.""RoleId"",act.""UserName"", act.""Email"", act.""Mobile"", act.""CountryId"",
                        CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
                        CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
                        act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
                        LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
                       -- LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
                        LEFT JOIN ""ProviderAvailability"" PAY ON PAY.""ProviderAvailabilityId"" = U.""ProviderAvailabilityId""
                        LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PAY.""ProviderId""
                        WHERE UPPER(act.""UserName"") = '{userName.Trim().ToUpper()}'";
                }
            }

            //if (!userName.Contains("@"))
            //{
            //    var mobile = userName.Split(":")[1];
            //    var countryId = userName.Split(":")[0];
            //    query = $@"SELECT act.""AccountId"", act.""RoleId"", act.""Email"", act.""Mobile"", act.""CountryId"",
            //            CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
            //            CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
            //            act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
            //            LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
            //            LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
            //            LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PL.""ProviderId""
            //            WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}' AND act.""RoleId"" IN ({accountTypes})";
            //}
            //else
            //{


            //    query = $@"SELECT act.""AccountId"", act.""RoleId"", act.""Email"", act.""Mobile"", act.""CountryId"",
            //            CASE WHEN PA.""Active"" IS NULL THEN act.""Active"" ELSE PA.""Active"" END ""Active"", 
            //            CASE WHEN PA.""IsLocked"" IS NULL THEN act.""IsLocked"" ELSE PA.""IsLocked"" END ""IsLocked"", 
            //            act.""SaltKey"", act.""FailedLoginAttempts""  FROM ""Account"" act
            //            LEFT JOIN ""User"" U ON U.""UserId"" = act.""ReferenceId""
            //            LEFT JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = U.""ProviderLocationId""
            //            LEFT JOIN ""Account"" PA ON PA.""ReferenceId"" = PL.""ProviderId""
            //            WHERE UPPER(act.""Email"") = '{userName.Trim().ToUpper()}' AND act.""RoleId"" IN ({accountTypes})";
            //}

            var account = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
            if (account == null || account.AccountId == 0)
            {
                return new Tuple<UserAccountStatus, int>(UserAccountStatus.InvalidAccount, 0);
            }

            if (account.IsLocked)
            {
                return new Tuple<UserAccountStatus, int>(UserAccountStatus.LockedAccount, 0);
            }

            if (!account.Active)
            {
                return new Tuple<UserAccountStatus, int>(UserAccountStatus.InactiveAccount, 0);
            }

            query = $@"SELECT * FROM ""AccountCredential"" WHERE ""AccountId"" = {account.AccountId} AND ""Active"" IS TRUE";
            var accountCredential = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountCredentialModel>(query);
            if (accountCredential == null || accountCredential.AccountCredentialId == 0 || !accountCredential.Active)
            {
                // await this.UpdateFailedLoginAttemptsAsync(account.Email, account.Mobile, account.CountryId, account.FailedLoginAttempts);
                return new Tuple<UserAccountStatus, int>(UserAccountStatus.InvalidAccount, 0);
            }

            var passwordHash = this.shaHelper.GenerateHash(password, account.SaltKey);
            if (passwordHash != accountCredential.PasswordHash)
            {
                // await this.UpdateFailedLoginAttemptsAsync(account.Email, account.Mobile, account.CountryId, account.FailedLoginAttempts);
                return new Tuple<UserAccountStatus, int>(UserAccountStatus.InvalidPassword, 0);
            }

            return new Tuple<UserAccountStatus, int>(UserAccountStatus.Success, account.AccountId);
        }

        /// <inheritdoc />
        public async Task<Tuple<UserAccountStatus, AccountModel>> ValidateAsync(string email, IEnumerable<AccountType> accountTypes)
        {
            var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""Email"", act.""RoleId"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
                        WHERE (UPPER(act.""Email"")) = '{email.Trim().ToUpper()}'";

            //var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""Email"", act.""RoleId"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
            //            WHERE (UPPER(act.""Email"")) = '{email.Trim().ToUpper()}' AND act.""RoleId"" IN ({string.Join(",", accountTypes.Select(m => (int)m))})";

            var account = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
            if (account == null || account.AccountId == 0)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InvalidAccount, null);
            }

            if (account.IsLocked)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.LockedAccount, null);
            }

            return !account.Active
                       ? new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InactiveAccount, null)
                       : new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.Success, account);
        }

        /// <inheritdoc />
        public async Task<Tuple<UserAccountStatus, AccountModel>> ValidateAsync(string mobile, int countryId, IEnumerable<AccountType> accountTypes)
        {

            var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""RoleId"", act.""Mobile"", act.""Email"", act.""CountryId"", cc.""CountryCode"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
                        JOIN ""Country"" cc ON cc.""CountryId""  = act.""CountryId"" AND cc.""Active"" IS TRUE
                        WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}'";

            //var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""RoleId"", act.""Mobile"", act.""Email"", act.""CountryId"", cc.""CountryCode"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
            //            JOIN ""Country"" cc ON cc.""CountryId""  = act.""CountryId"" AND cc.""Active"" IS TRUE
            //            WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}' AND act.""RoleId"" IN ({string.Join(",", accountTypes.Select(m => (int)m))})";

            var account = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
            if (account == null || account.AccountId == 0)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InvalidAccount, null);
            }

            if (account.IsLocked)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.LockedAccount, null);
            }

            return !account.Active
                       ? new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InactiveAccount, null)
                       : new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.Success, account);
        }

        /// <inheritdoc />
        public Task<UserAccount> FindAsync(int accountId)
        {
            var query = $@"SELECT pat.""UMRNo"",act.""AccountId"", (CASE WHEN act.""RoleId"" IN ({(int)Roles.Nurse}, {(int)Roles.Receptionist}) THEN PA.""ProviderId"" ELSE act.""ReferenceId"" END ) ""ReferenceId"", act.""FullName"", act.""Email"", act.""Mobile"", act.""LastLoginDate"", act.""RoleId"", rl.""RoleName"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) THEN (CASE WHEN usr.""ThumbnailUrl"" IS NOT NULL THEN usr.""ThumbnailUrl"" ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN (CASE WHEN pr.""ThumbnailUrl"" IS NOT NULL THEN pr.""ThumbnailUrl"" ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END)
                        END) ""ThumbnailUrl"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) THEN usr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN pr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""Guid""::text
                        END) ""Guid"", act.""CountryId"", cun.""CountryCode"", cun.""CountryName"", act.""IsAgreed"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) AND usr.""CountryId"" IS NULL THEN TRUE
                        WHEN act.""RoleId"" = {(int)Roles.Provider} AND pr.""ApprovalStatus"" IS NULL THEN TRUE
                        WHEN act.""RoleId"" = {(int)Roles.Patient} AND (pat.""Gender"" IS NULL OR pat.""Mobile"" IS NULL OR pat.""CountryId"" IS NULL OR pat.""Age"" IS NULL) THEN TRUE ELSE FALSE
                        END) ""IsNew"",
                        (CASE WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""ReferralCode"" ELSE '' END) ""ReferralCode""
                        FROM ""Account"" act
                        JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = act.""CountryId"" AND cun.""Active"" IS TRUE
                        LEFT JOIN ""User"" usr ON usr.""UserId"" = act.""ReferenceId"" AND usr.""Active"" IS TRUE
                        LEFT JOIN ""Patient"" pat ON pat.""PatientId"" = act.""ReferenceId"" AND pat.""Active"" IS TRUE
                        LEFT JOIN ""Provider"" pr ON pr.""ProviderId"" = act.""ReferenceId"" AND pr.""Active"" IS TRUE
                        LEFT JOIN ""User"" pra ON pra.""UserId"" = act.""ReferenceId"" AND pra.""Active"" IS TRUE
                        --LEFT JOIN ""ProviderLocation"" prl ON prl.""ProviderLocationId"" = pra.""ProviderLocationId"" AND prl.""Active"" IS TRUE
                        LEFT JOIN ""ProviderAvailability"" PA ON PA.""ProviderAvailabilityId"" = pra.""ProviderAvailabilityId"" AND PA.""Active"" IS TRUE
                        WHERE act.""AccountId"" = {accountId}";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<UserAccount>(query);
        }

        /// <inheritdoc />
        public Task<UserAccount> FindByLocationIdAsync(int accountId, int locationId)
        {
            var query = $@"SELECT pat.""UMRNo"",act.""AccountId"", (CASE WHEN act.""RoleId"" IN ({(int)Roles.Nurse}, {(int)Roles.Receptionist}) THEN PA.""ProviderId"" ELSE act.""ReferenceId"" END ) ""ReferenceId"", act.""FullName"", act.""Email"", act.""Mobile"", act.""LastLoginDate"", act.""RoleId"", rl.""RoleName"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) THEN (CASE WHEN usr.""ThumbnailUrl"" IS NOT NULL THEN usr.""ThumbnailUrl"" ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN (CASE WHEN pr.""ThumbnailUrl"" IS NOT NULL THEN pr.""ThumbnailUrl"" ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END)
                        END) ""ThumbnailUrl"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) THEN usr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN pr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""Guid""::text
                        END) ""Guid"", act.""CountryId"", cun.""CountryCode"", cun.""CountryName"", act.""IsAgreed"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Nurse}, {(int)Roles.Receptionist},{(int)Roles.SymptomCreator}) AND usr.""CountryId"" IS NULL THEN TRUE
                        WHEN act.""RoleId"" = {(int)Roles.Provider} AND pr.""ApprovalStatus"" IS NULL THEN TRUE
                        WHEN act.""RoleId"" = {(int)Roles.Patient} AND (pat.""Gender"" IS NULL OR pat.""Mobile"" IS NULL OR pat.""CountryId"" IS NULL OR pat.""Age"" IS NULL) THEN TRUE ELSE FALSE
                        END) ""IsNew"",
                        (CASE WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""ReferralCode"" ELSE '' END) ""ReferralCode"",
                        l.""LocationId"", l.""Name"" ""LocationName""
                        FROM ""Account"" act
                        JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                        JOIN ""LocationAccountMap"" la on la.""AccountId"" = act.""AccountId""
                        JOIN ""Location"" l on l.""LocationId"" = la.""LocationId""
                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = act.""CountryId"" AND cun.""Active"" IS TRUE
                        LEFT JOIN ""User"" usr ON usr.""UserId"" = act.""ReferenceId"" AND usr.""Active"" IS TRUE
                        LEFT JOIN ""Patient"" pat ON pat.""PatientId"" = act.""ReferenceId"" AND pat.""Active"" IS TRUE
                        LEFT JOIN ""Provider"" pr ON pr.""ProviderId"" = act.""ReferenceId"" AND pr.""Active"" IS TRUE
                        LEFT JOIN ""User"" pra ON pra.""UserId"" = act.""ReferenceId"" AND pra.""Active"" IS TRUE
                        --LEFT JOIN ""ProviderLocation"" prl ON prl.""ProviderLocationId"" = pra.""ProviderLocationId"" AND prl.""Active"" IS TRUE
                        LEFT JOIN ""ProviderAvailability"" PA ON PA.""ProviderAvailabilityId"" = pra.""ProviderAvailabilityId"" AND PA.""Active"" IS TRUE
                        WHERE act.""AccountId"" = {accountId} AND l.""LocationId"" = {locationId}";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<UserAccount>(query);
        }

        /// <inheritdoc />
        public async Task<Menu.ViewModel> GetDefaultMenuAsync(int? menuId)
        {
            var query = $@"SELECT M
	                        .""MainPage"",
	                        M.""SubPage"",
                            M.""SubPage"" ""DisplayName"",
	                        M.""Url"",
	                        M.""Count"",
	                        M.""Priority"",
	                        M.""GeneralClasses"",
	                        M.""IconClasses"",
	                        M.""MenuTypeId"" 
                        FROM
	                        ""Menu"" M
                        WHERE m.""MenuId"" = {menuId}";

            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<Menu.ViewModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<string>> GetMenuButtonCodesAsync(int roleId)
        {
            var query = $@"SELECT M.""Code""
                        FROM
	                        ""MenuButton"" M
                        LEFT JOIN ""MenuButtonRelationship"" r on r.""MenuButtonId"" = M.""MenuButtonId""
                        WHERE r.""RoleId"" = {roleId}";

            return await this.unitOfWork.Current.QueryAsync<string>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<Menu.ViewModel>> FetchMenuAsync(int accountId, bool isFullAccess)
        {
            var query = $@"SELECT DISTINCT M
	                        .""MainPage"",
	                        M.""SubPage"",
	                        M.""Category"",
	                        M.""SubPage"" ""DisplayName"",
	                        M.""Url"",
	                        M.""Count"",
	                        M.""Priority"",
	                        M.""GeneralClasses"",
	                        M.""IconClasses"",
	                        M.""MenuTypeId"" ,
                            M.""EncounterKey""
                        FROM";
            var subQuery = string.Empty;
            if (isFullAccess)
            {
                subQuery += @" ""Menu"" m";
                //where m.""Url"" not ILike '%:id%'
            }
            else
            {
                subQuery += $@" ""MenuRelationship"" r
	                        JOIN ""Menu"" M ON M.""MenuId"" = r.""MenuId""
	                        JOIN ""Role"" o ON o.""RoleId"" = r.""RoleId""
	                        JOIN ""Account"" A ON A.""RoleId"" = o.""RoleId""
                        WHERE ""AccountId"" = {accountId} AND M.""MenuTypeId"" <> 4 ";
            }

            var records = await this.unitOfWork.Current.QueryAsync<Menu.ViewModel>(query + subQuery);
            return records;

            //var mainPages = string.Join(",", records.Select(x => "'" + x.MainPage + "'").Distinct());
            //query += $@" ""Menu"" m WHERE m.""MenuTypeId"" = 4 AND m.""MainPage"" IN ({mainPages}) ";
            //var hiddenMenus = await this.unitOfWork.Current.QueryAsync<Menu.ViewModel>(query);
            //var newRecords = records.ToList();
            //newRecords.AddRange(hiddenMenus);
            //return newRecords;
        }

        /// <inheritdoc />
        public async Task<Menu.MenuAccessModel> IsMenuFullAccessAsync(int roleId)
        {
            var query = $@"SELECT
	                        ""IsFullAccess"", 
	                        ""InitialRouteMenuId""
                        FROM
	                        ""MenuAccess"" A 
                        WHERE
	                        A.""RoleId"" = {roleId}";

            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<Menu.MenuAccessModel>(query);
        }

        /// <inheritdoc />
        public Task<RoleModel> GetRoleAsync(int accountId)
        {
            var query = $@"SELECT r.""RoleId"", r.""RoleName"" FROM ""Account"" act
                        JOIN ""Role"" r ON r.""RoleId"" = act.""RoleId"" AND r.""Active"" IS TRUE
                        WHERE act.""AccountId"" = {accountId}";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<RoleModel>(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateAgreementStatusAsync(int accountId)
        {
            var where = $@" WHERE ""AccountId"" = '{accountId}' ";
            var query = $@"UPDATE ""Account"" SET ""IsAgreed"" = TRUE, ""AgreedDate"" = NOW() at time zone 'UTC' {where}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task UpdateLoginSuccessfulAsync(int accountId)
        {
            var where = $@" WHERE ""AccountId"" = '{accountId}' ";
            var query = $@"UPDATE ""Account"" SET ""FailedLoginAttempts"" = 0, ""IsLocked"" = FALSE, ""OTPVerified"" = TRUE, ""LastLoginDate"" = NOW() at time zone 'UTC' {where}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<Guid> FindGuidAsync(int accountId)
        {
            var where = $@" WHERE ""AccountId"" = {accountId} ";
            var query = $@"select ""Guid"" from ""Account"" {where}";
            return this.unitOfWork.Current.QuerySingleOrDefaultAsync<Guid>(query);
        }

        /// <inheritdoc />
        public Task<Guid> FindGuidAsync(int referenceId, Roles role)
        {
            var where = $@" WHERE ""ReferenceId"" = {referenceId} and ""RoleId""={(int)role} ";
            var query = $@"select ""Guid"" from ""Account"" {where}";
            return this.unitOfWork.Current.QuerySingleOrDefaultAsync<Guid>(query);
        }

        /// <inheritdoc />
        public Task<AccountModel> FindGuidAsync(string umrNumber, Roles role)
        {
            var where = $@" WHERE p.""UMRNo"" = '{umrNumber}' and a.""RoleId""={(int)role} ";
            var query = $@"select a.""ReferenceId"",a.""Guid"" as ""PatientGuid"" from ""Account"" a join ""Patient"" p on a.""ReferenceId"" = p.""PatientId"" {where}";
            return this.unitOfWork.Current.QuerySingleOrDefaultAsync<AccountModel>(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<int>> FindAccountIdAsync(string referenceIds)
        {
            var where = $@" WHERE ""ReferenceId"" in ({referenceIds})  ";
            var query = $@"select ""AccountId"" from ""Account"" {where}";
            return this.unitOfWork.Current.QueryAsync<int>(query);
        }

        /// <inheritdoc />
        public Task UpdateFailedLoginAttemptsAsync(string email, string mobile, int countryId, short failedLoginAttempts)
        {
            var where = $@" WHERE ""Email"" = '{email}' AND ""Mobile"" = '{mobile}' AND ""CountryId"" = '{countryId}' ";
            var locked = failedLoginAttempts >= 19;
            var query = $@"UPDATE ""Account"" SET ""FailedLoginAttempts"" = ""FailedLoginAttempts"" + 1, ""IsLocked"" = {locked}, ""LastFailedLoginDate"" = NOW() at time zone 'UTC' {where}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<IEnumerable<AccountModel>> FetchAsync(UserFilterModel model)
        {
            var where = @" WHERE 1=1 ";
            if (!string.IsNullOrEmpty(model.FullName))
            {
                where += $@" AND act.""FullName"" ILIKE '%{model.FullName}%'";
            }

            if (!string.IsNullOrEmpty(model.Email))
            {
                where += $@" AND act.""Email"" ILIKE '%{model.Email}%'";
            }

            if (!string.IsNullOrEmpty(model.Mobile))
            {
                where += $@" AND act.""Mobile"" ILIKE '%{model.Mobile}%'";
            }

            if (!string.IsNullOrEmpty(model.CreatedDate))
            {
                where += $@" AND act.""CreatedDate""::DATE = '{model.CreatedDate}'::DATE ";
            }

            if (model.RoleId != null)
            {
                where += $@" AND act.""RoleId"" = '{model.RoleId}'";
            }
            else
            {
                where += $@" AND act.""RoleId"" <> {(int)Roles.Patient}";
            }

            if (model.LastLoginDate != null)
            {
                where += $@" AND act.""LastLoginDate""::date = '{model.LastLoginDate}'::date";
            }

            if (model.CountryId != null)
            {
                where += $@" AND act.""CountryId"" = '{model.CountryId}'";
            }

            if (model.Status != null)
            {
                switch (model.Status)
                {
                    case 'A':
                        where += $@" AND act.""Active"" IS TRUE AND act.""IsLocked"" IS FALSE ";
                        break;
                    case 'D':
                        where += $@" AND act.""Active"" IS FALSE ";
                        break;
                    case 'L':
                        where += $@" AND act.""IsLocked"" IS TRUE ";
                        break;
                }
            }

            var query = $@"SELECT COUNT(act.*) OVER() AS ""TotalItems"", act.""AccountId"", act.""ReferenceId"", act.""FullName"", act.""UserName"", act.""Email"", act.""Mobile"", act.""LastLoginDate"", act.""RoleId"", rl.""RoleName"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Support}, {(int)Roles.Nurse}, {(int)Roles.Receptionist}, {(int)Roles.Accountant}) THEN (CASE WHEN usr.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', usr.""Guid"", '/', usr.""ThumbnailUrl"") ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN (CASE WHEN pr.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pr.""Guid"", '/', pr.""ThumbnailUrl"") ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END)
                        END) ""ThumbnailUrl"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Support}, {(int)Roles.Nurse}, {(int)Roles.Receptionist}, {(int)Roles.Accountant}) THEN usr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN pr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""Guid""::text
                        END) ""Guid"", act.""CountryId"", cun.""CountryCode"", cun.""CountryName"", act.""Active"", act.""IsLocked"", act.""CreatedDate"",
                        (CASE WHEN act.""Active"" IS FALSE THEN 'D' WHEN act.""IsLocked"" IS TRUE THEN 'L' ELSE 'A' END) ""Status"",
                        (Select  string_agg(l.""LocationId""::text, ', ') as ""LocationIdentifiers""
                                        from ""LocationAccountMap"" la
                                        join ""Location"" l ON l.""LocationId"" = la.""LocationId"" WHERE la.""AccountId"" = act.""AccountId"")	
                              
                        FROM ""Account"" act
                        JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = act.""CountryId"" AND cun.""Active"" IS TRUE
                        LEFT JOIN ""User"" usr ON usr.""UserId"" = act.""ReferenceId"" AND usr.""Active"" IS TRUE
                        LEFT JOIN ""Patient"" pat ON pat.""PatientId"" = act.""ReferenceId"" AND pat.""Active"" IS TRUE
                        LEFT JOIN ""Provider"" pr ON pr.""ProviderId"" = act.""ReferenceId"" AND pr.""Active"" IS TRUE
                        {where} ORDER BY act.""AccountId"" DESC ";

            if (model.PageIndex <= 0)
            {
                return this.unitOfWork.Current.QueryAsync<AccountModel>(query);
            }

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);

            return this.unitOfWork.Current.QueryAsync<AccountModel>(query);
        }

        /// <inheritdoc />
        public Task<AccountModel> FindUserAsync(int userId)
        {
            var where = $@" WHERE act.""ReferenceId"" ={userId} AND  act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Support}, {(int)Roles.Nurse}, {(int)Roles.Receptionist}, {(int)Roles.Accountant}) ";

            var query = $@"SELECT act.""AccountId"", act.""ReferenceId"", act.""FullName"", act.""Email"", act.""Mobile"", act.""LastLoginDate"", act.""RoleId"", rl.""RoleName"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Support}, {(int)Roles.Nurse}, {(int)Roles.Receptionist}, {(int)Roles.Accountant}) THEN (CASE WHEN usr.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', usr.""Guid"", '/', usr.""ThumbnailUrl"") ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN (CASE WHEN pr.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pr.""Guid"", '/', pr.""ThumbnailUrl"") ELSE '' END)
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END)
                        END) ""ThumbnailUrl"",
                        (CASE
                        WHEN act.""RoleId"" in ({(int)Roles.SuperAdmin}, {(int)Roles.Administrator}, {(int)Roles.Support}, {(int)Roles.Nurse}, {(int)Roles.Receptionist}, {(int)Roles.Accountant}) THEN usr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Provider} THEN pr.""Guid""::text
                        WHEN act.""RoleId"" = {(int)Roles.Patient} THEN pat.""Guid""::text
                        END) ""Guid"", act.""CountryId"", cun.""CountryCode"", cun.""CountryName"", act.""Active"", act.""IsLocked"", act.""CreatedDate"",
                        (CASE WHEN act.""Active"" IS FALSE THEN 'D' WHEN act.""IsLocked"" IS TRUE THEN 'L' ELSE 'A' END) ""Status""
                        FROM ""Account"" act
                        JOIN ""Role"" rl ON rl.""RoleId"" = act.""RoleId"" AND rl.""Active"" IS TRUE
                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = act.""CountryId"" AND cun.""Active"" IS TRUE
                        LEFT JOIN ""User"" usr ON usr.""UserId"" = act.""ReferenceId"" AND usr.""Active"" IS TRUE
                        LEFT JOIN ""Patient"" pat ON pat.""PatientId"" = act.""ReferenceId"" AND pat.""Active"" IS TRUE
                        LEFT JOIN ""Provider"" pr ON pr.""ProviderId"" = act.""ReferenceId"" AND pr.""Active"" IS TRUE
                        {where} ORDER BY act.""AccountId"" DESC ";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
        }

        /// <inheritdoc />
        public Task<int> ModifyStatusAsync(int accountId, int modifiedBy, bool status)
        {
            var where = $@" WHERE  ""AccountId"" = {accountId} ";

            var query = $@"UPDATE ""Account"" SET ""Active"" = {status}, ""ModifiedBy"" = {modifiedBy}, ""ModifiedDate"" = NOW() at time zone 'UTC' {where}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> LockedStatusAsync(int accountId, int modifiedBy, bool status)
        {
            var where = $@" WHERE  ""AccountId"" = {accountId} ";

            var query = $@"UPDATE ""Account"" SET ""IsLocked"" = {status}, ""ModifiedBy"" = {modifiedBy}, ""ModifiedDate"" = NOW() at time zone 'UTC' {where}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> InsertLoginAsync(LoginModel model)
        {
            var data = new Login
            {
                Password = model.Password,
                Username = model.Username,
                DeviceType = model.DeviceType,
                DeviceToken = model.DeviceToken,
                DeviceId = model.DeviceId,
                AccountTypes = model.AccountTypes,
                CreatedDate = model.CreatedDate
            };
            return this.unitOfWork.Login.InsertAsync(data);
        }

        /// <inheritdoc />
        public Task<AccountModel> GetAccountDetailAsync(string userName, string roles)
        {
            string where = $@"where A.""RoleId"" IN ({roles}) ";
            if (!userName.Contains("@"))
            {
                var mobile = userName.Split(":")[1];
                var countryId = userName.Split(":")[0];
                where += $@" and A.""Mobile"" = '{mobile}' AND A.""CountryId"" = '{countryId}'";
            }
            else
            {
                if (userName.Contains("."))
                {
                    where += $@" and UPPER(A.""Email"") = '{userName.Trim().ToUpper()}'";
                }
                else
                {
                    where += $@" and UPPER(A.""UserName"") = '{userName.Trim().ToUpper()}'";
                }

            }

            var query = $@"Select A.*,R.""RoleName"", CASE WHEN AC.""PasswordHash"" IS NULL THEN FALSE ELSE TRUE END AS ""PasswordExist"" from ""Account"" A 
                            join ""Role"" R on R.""RoleId"" = A.""RoleId""
                            LEFT JOIN ""AccountCredential"" AC ON A.""AccountId"" = AC.""AccountId"" AND AC.""Active"" IS TRUE {where}";

            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
        }

        /// <inheritdoc />
        public async Task<List<int>> GetAllRolesAsync()
        {
            return (await this.unitOfWork.Roles.FindAllAsync()).Select(x => x.RoleId).ToList();
        }


        /// <inheritdoc />
        public async Task<Role> GetPatientRolesAsync()
        {
            return await this.unitOfWork.Roles.FindAsync(x => x.RoleId == 4);

        }

        /// <inheritdoc />
        public async Task<int> UpdateLastLoginDateAsync(int accountId)
        {
            var record = await this.unitOfWork.Accounts.FindAsync(x => x.AccountId == accountId);

            if (record == null) return -1;
            record.LastLoginDate = DateTime.Now;
            return await this.unitOfWork.Accounts.UpdateAsync(record);
        }

        /// <inheritdoc />
        public Task<AccountModel> FindPatientByMobileAsync(string mobile)
        {
            var query = $@"Select ""FullName"" From ""Account"" Where ""Mobile"" ='{mobile}' and ""RoleId"" = 4 ";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> ModifyAccountsLocation(int[] locationIds, int accountId)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            var getAccountDetails = await this.unitOfWork.Accounts.FindAsync(a => a.AccountId == accountId);
            if (getAccountDetails == null)
            {
                return -1;
            }
            var isProvider = getAccountDetails.RoleId == (int)Roles.Provider;
            try
            {
                var deleteQuerry = $@" Delete from ""LocationAccountMap"" where ""AccountId""= {accountId}";
                var res = await this.unitOfWork.Current.ExecuteAsync(deleteQuerry, transaction);
                if (res < 0)
                {
                    transaction.Rollback();
                    return 0;
                }
            }
            catch (Exception)
            {
                transaction.Rollback();
                return -1;

            }
            foreach (var locationId in locationIds.ToList())
            {
                var location = new LocationAccountMap
                {
                    AccountId = accountId,
                    LocationId = Convert.ToInt32(locationId)
                };
                var locationInsertId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                if (locationInsertId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                //if (isProvider)
                //{
                //    var checkInLocation = await this.unitOfWork.ProviderLocations.FindAsync(p => p.ProviderId == getAccountDetails.ReferenceId && p.LocationId == locationId);
                //    if (checkInLocation == null)
                //    {
                //        var providerLocationModel = new ProviderLocation
                //        {
                //            LocationId = locationId,
                //            Active = true,
                //            CreatedBy = accountId,
                //            CreatedDate = DateTime.Now,
                //            ProviderId = getAccountDetails.ReferenceId
                //        };

                //        var id = await this.unitOfWork.ProviderLocations.InsertAsync(providerLocationModel, transaction);
                //        if (id == 0)
                //        {
                //            transaction.Rollback();
                //            return 0;
                //        }
                //    }
                //}
                if (isProvider)
                {
                    var checkInLocation = await this.unitOfWork.ProviderAvailability.FindAsync(p => p.ProviderId == getAccountDetails.ReferenceId && p.LocationId == locationId);
                    if (checkInLocation == null)
                    {
                        var providerLocationModel = new ProviderAvailability
                        {
                            LocationId = locationId,
                            Active = true,
                            CreatedBy = accountId,
                            CreatedDate = DateTime.Now,
                            ProviderId = getAccountDetails.ReferenceId
                        };

                        var id = await this.unitOfWork.ProviderAvailability.InsertAsync(providerLocationModel, transaction);
                        if (id == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }
                    }
                }

            }
            transaction.Commit();
            return 1;
        }

        public async Task<bool> GetIsNurse(IdRequest model)
        {
            var query = $@" SELECT ""RoleConcept"" FROM ""Account""a 
                            JOIN ""Role"" r on r.""RoleId"" = a.""RoleId"" WHERE a.""AccountId"" = {model.Id} ";
            var roleConcept = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return roleConcept == "N";
        }

        public async Task<IEnumerable<AccountModel>> GetAccountDetailListAsync(string mobile, string roles, string userName)
        {
            string where = $@"where A.""RoleId"" IN ({roles}) ";
            if (!userName.Contains("@"))
            {
                var mobileNo = userName.Split(":")[1];
                var countryId = userName.Split(":")[0];
                where += $@" and A.""Mobile"" = '{mobileNo}' AND A.""CountryId"" = '{countryId}'";
            }
            else
            {
                if (userName.Contains("."))
                {
                    where += $@" and UPPER(A.""Email"") = '{userName.Trim().ToUpper()}'";
                }
                else
                {
                    where += $@" and UPPER(A.""UserName"") = '{userName.Trim().ToUpper()}'";
                }

            }
            var query = $@"Select A.*,R.""RoleName"", CASE WHEN AC.""PasswordHash"" IS NULL THEN FALSE ELSE TRUE END AS ""PasswordExist"" from ""Account"" A 
                            join ""Role"" R on R.""RoleId"" = A.""RoleId""
                            LEFT JOIN ""AccountCredential"" AC ON A.""AccountId"" = AC.""AccountId"" AND AC.""Active"" IS TRUE {where}";
            return await this.unitOfWork.Current.QueryAsync<AccountModel>(query);
        }

        public async Task<IEnumerable<AccountModel>> GetPatientAccountDetailListAsync(string mobile, string roles, string userName)
        {
            string where = $@"where A.""RoleId"" IN ({roles}) ";
            if (userName.Contains(":") && !userName.Contains("@") && !userName.ToLower().Contains("umr"))
            {
                var mobileNo = userName.Split(":")[1];
                var countryId = userName.Split(":")[0];
                where += $@" and A.""Mobile"" = '{mobileNo}' AND A.""CountryId"" = '{countryId}'";
            }
            else
            {
                if (userName.Contains("."))
                {
                    where += $@" and UPPER(A.""Email"") = '{userName.Trim().ToUpper()}'";
                }
                else if (userName.ToLower().Contains("umr"))
                {
                    where += $@" and UPPER(p.""UMRNo"") = '{userName.Trim().ToUpper()}'";
                }
                else
                {
                    where += $@" and UPPER(A.""UserName"") = null";
                }

            }
            var query = $@"Select A.*,R.""RoleName"", CASE WHEN AC.""PasswordHash"" IS NULL THEN FALSE ELSE TRUE END AS ""PasswordExist"" from ""Account"" A 
                            left join ""Patient"" as P on A.""ReferenceId"" = P.""PatientId""
                            join ""Role"" R on R.""RoleId"" = A.""RoleId""
                            LEFT JOIN ""AccountCredential"" AC ON A.""AccountId"" = AC.""AccountId"" AND AC.""Active"" IS TRUE  {where}";
            return await this.unitOfWork.Current.QueryAsync<AccountModel>(query);
        }
        public async Task<Tuple<UserAccountStatus, AccountModel>> ValidatePatientAsync(string email, IEnumerable<AccountType> accountTypes, int? accountId)
        {
            var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""Email"", act.""RoleId"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
                        WHERE (UPPER(act.""Email"")) = '{email.Trim().ToUpper()}' and act.""AccountId"" = {accountId}";


            var account = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
            if (account == null || account.AccountId == 0)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InvalidAccount, null);
            }

            if (account.IsLocked)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.LockedAccount, null);
            }

            return !account.Active
                       ? new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InactiveAccount, null)
                       : new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.Success, account);
        }

        public async Task<Tuple<UserAccountStatus, AccountModel>> ValidatePatientAsync(string mobile, int countryId, IEnumerable<AccountType> accountTypes, int? accountId)
        {
            var query = $@"SELECT act.""AccountId"", act.""FullName"", act.""RoleId"", act.""Mobile"", act.""Email"", act.""CountryId"", cc.""CountryCode"", act.""Active"", act.""IsLocked"", act.""FailedLoginAttempts"" FROM ""Account"" act
                        JOIN ""Country"" cc ON cc.""CountryId""  = act.""CountryId"" AND cc.""Active"" IS TRUE
                        WHERE act.""Mobile"" = '{mobile}' AND act.""CountryId"" = '{countryId}' and act.""AccountId"" = {accountId}";


            var account = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AccountModel>(query);
            if (account == null || account.AccountId == 0)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InvalidAccount, null);
            }

            if (account.IsLocked)
            {
                return new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.LockedAccount, null);
            }

            return !account.Active
                       ? new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.InactiveAccount, null)
                       : new Tuple<UserAccountStatus, AccountModel>(UserAccountStatus.Success, account);
        }
        public Task<int> GetReferenceAsync(int accountId)
        {
            var query = $@"SELECT ""ReferenceId"" from ""Account""
                        WHERE ""AccountId"" = {accountId} and ""RoleId""=3";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<PatientModel>> FetchCallerUserDetailsAsync(IdRequest model)
        {
            if (!string.IsNullOrEmpty(model.CallerUser))
            {
                var checkCallerUserDetails = await this.unitOfWork.Accounts.FindAsync(m => m.CallerUser == model.CallerUser);
                if (checkCallerUserDetails == null)
                {
                    return null;
                }
            }
            var where = @"WHERE 1 = 1 ";

            if (!string.IsNullOrEmpty(model.Mobile))
            {
                where += $@" AND pat.""Mobile"" ILIKE '%{model.Mobile}%' ";
            }

            var query = $@"SELECT Count(*) OVER() AS ""TotalItems"" ,* from (Select distinct l.""LocationId"", l.""NameLoc"" ""LocationName"", pat.""PatientId"", pat.""Guid"", pat.""ReferralCode"", act.""AccountId"", pat.""Salutation"", pat.""FullName"", pat.""FatherOrHusband"",
                                pat.""UMRNo"", pat.""Gender"", pat.""DateOfBirth"", pat.""Age"", pat.""CountryId"", pat.""Email"", pat.""Mobile"", pat.""Active"", pat.""CreatedDate"",pat.""BloodGroup"",pat.""PaymentStatus"",
                               pat.""BirthMark1"",pat.""BirthMark2"",pat.""ParentPatientId"",
                                pat.""PaymentNumber"", pat.""PayTypeId"",HWC.""HWCName"",HWC.""HWCPatientId"",HWC.""Description"",HWC.""RowColor"",
                                (CASE WHEN pat.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}','/', pat.""Guid"", '/', pat.""ProfileImageUrl"") ELSE '' END) AS ""ProfileImageUrl"",
                         (CASE WHEN pat.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', pat.""Guid"", '/', pat.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl"",
                                ctr.""CountryName"", ctr.""CountryCode"", ctr.""ISOCode"", crt.""FullName"" AS ""CreatedByName"", act.""IsLocked"", act.""OTPVerified"", act.""ManualVerified""
                                ,CASE WHEN acs.""AccountSessionId"" IS NULL THEN FALSE ELSE TRUE END AS ""IsOnline""
                            ,CASE WHEN pat.""REGNO""::text IS NULL THEN NULL ELSE pat.""REGNO""::text END 
                                FROM ""Patient"" pat
                                JOIN ""Account"" act ON act.""ReferenceId"" = pat.""PatientId"" AND act.""RoleId"" = '{(int)Roles.Patient}'
                                left JOIN ""LocationAccountMap"" la on la.""AccountId"" = act.""AccountId""
                                left JOIN ""Location"" l on l.""LocationId"" = la.""LocationId""
                                LEFT JOIN ""Account"" crt ON crt.""AccountId"" = pat.""CreatedBy"" AND crt.""Active"" IS TRUE
                                LEFT JOIN ""Country"" ctr ON ctr.""CountryId"" = pat.""CountryId"" AND ctr.""Active"" IS TRUE
                                left join ""AccountSession"" acs on acs.""AccountId"" = act.""AccountId""  AND acs.""Active"" IS TRUE 
                                left join ""HWCPatient""  HWC on HWC.""HWCPatientId"" = pat.""HWCPatientId""
                                {where}
                                ORDER BY pat.""PatientId"" DESC) A";


            var patientModels = await this.unitOfWork.Current.QueryAsync<PatientModel>(query);
            return patientModels;


        }
    }
}