namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Configurations;
    using Domain.Entities;
    using Domain.Helpers;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.Library.Enums;
    using Shared.UserModels;
    using Shared.UserModels.Filters;

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

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

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

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

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

        public async Task<Provider> GetRawAsync(int id)
        {
            return await this.unitOfWork.Providers.FindAsync(x => x.ProviderId == id);
        }

        /// <inheritdoc />
        public async Task<int> RegisterAsync(ProviderRegistrationModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            var provider = new Provider
            {
                FirstName = model.FirstName,
                LastName = model.LastName,
                FullName = CoreFilter.FullName(model.FirstName, string.Empty, model.LastName),
                FriendlyName = model.FriendlyName,
                DateOfBirth = model.DateOfBirth,
                Age = model.Age,
                ProviderNo = model.ProviderNo,
                CreatedBy = null,
                CreatedDate = DateTime.UtcNow,
                Active = true,
                Theme = "light",
                ApprovalStatus = null,
                Guid = Guid.NewGuid()
            };

            if (model.CountryId == null && model.Username.Contains("@"))
            {
                provider.Email = model.Username;
            }
            else
            {
                provider.Mobile = model.Username;
                provider.CountryId = Convert.ToInt32(model.CountryId);
            }

            provider.ProviderId = await this.unitOfWork.Providers.InsertAsync(provider, transaction);
            if (provider.ProviderId == 0)
            {
                transaction.Rollback();
                return 0;
            }

            var providerName = provider.FullName + "(" + provider.FriendlyName + ")";
            var saltKey = CoreFilter.Random(10);
            var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == provider.Email && m.Mobile == provider.Mobile && m.CountryId == provider.CountryId, transaction);
            if (existingAccount != null && existingAccount.AccountId != 0)
            {
                saltKey = existingAccount.SaltKey;
            }

            var account = new Account
            {
                RoleId = (int)Roles.Provider,
                ReferenceId = provider.ProviderId,
                SaltKey = saltKey,
                CreatedDate = DateTime.UtcNow,
                Mobile = provider.Mobile,
                CountryId = provider.CountryId,
                Email = provider.Email,
                FullName = providerName,
                IsAgreed = model.IsAgreed,
                AgreedDate = model.IsAgreed ? DateTime.UtcNow : (DateTime?)null,
                Active = true,
                Guid = provider.Guid
            };

            account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
            if (account.AccountId == 0)
            {
                transaction.Rollback();
                return 0;
            }

            var passwordHash = this.shaHelper.GenerateHash(model.Password, account.SaltKey);
            var query = new AccountsCredential(account, passwordHash).Query;

            var inserted = await this.unitOfWork.Current.ExecuteAsync(query, transaction);
            if (inserted == 0)
            {
                transaction.Rollback();
                return 0;
            }

            transaction.Commit();
            return provider.ProviderId;
        }

        /// <inheritdoc />
        public async Task<Tuple<int, Guid?>> SelfRegisterAsync(SelfRegistrationModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var provider = new Provider
                {
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    FullName = CoreFilter.FullName(model.FirstName, string.Empty, model.LastName),
                    FriendlyName = model.FriendlyName,
                    ProviderNo = model.ProviderNo,
                    CreatedBy = null,
                    CreatedDate = DateTime.UtcNow,
                    Active = false,
                    Theme = "light",
                    ApprovalStatus = null,
                    Email = model.Email,
                    CountryId = model.CountryId,
                    Mobile = model.Mobile,
                    Experience = model.Experience,
                    Languages = model.Languages,
                    Guid = Guid.NewGuid()
                };

                provider.ProviderId = await this.unitOfWork.Providers.InsertAsync(provider, transaction);
                if (provider.ProviderId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, provider.Guid);
                }

                var providerName = provider.FullName + "(" + provider.FriendlyName + ")";
                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == provider.Email && m.Mobile == provider.Mobile && m.CountryId == provider.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId != 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                var account = new Account
                {
                    RoleId = (int)Roles.Provider,
                    ReferenceId = provider.ProviderId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.UtcNow,
                    Mobile = provider.Mobile,
                    CountryId = provider.CountryId,
                    Email = provider.Email,
                    FullName = providerName,
                    IsAgreed = model.IsAgreed,
                    AgreedDate = model.IsAgreed ? DateTime.UtcNow : (DateTime?)null,
                    Active = false,
                    Guid = provider.Guid
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, Guid?>(0, account.Guid);
                }

                transaction.Commit();

                if (!string.IsNullOrEmpty(model.Specializations))
                {
                    var query1 = $@"UPDATE ""Provider"" SET ""Specializations"" = ARRAY[{model.Specializations}] WHERE ""ProviderId""= '{provider.ProviderId}'";
                    await this.unitOfWork.Current.ExecuteAsync(query1);
                }

                return new Tuple<int, Guid?>(provider.ProviderId, account.Guid);
            }
        }

        /// <inheritdoc />
        public async Task<int> OTPVerificationAsync(SelfRegistrationModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var provider = await this.unitOfWork.Providers.FindAsync(m => m.CountryId == model.CountryId && m.Mobile == model.Mobile);
                provider.Active = true;

                var response = await this.unitOfWork.Providers.UpdateAsync(provider, transaction);
                if (response == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                var account = await this.unitOfWork.Accounts.FindAsync(m => m.ReferenceId == provider.ProviderId && m.RoleId == (int)Roles.Provider);
                account.Active = true;

                response = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                if (response == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return account.AccountId;
            }
        }

        /// <inheritdoc />
        public async Task<ProviderModel> ApproveAsync(int providerId)
        {
            var provider = await this.unitOfWork.Providers.FindAsync(m => m.ProviderId == providerId);
            provider.ApprovalStatus = true;
            provider.Active = true;
            provider.ApprovedDate = DateTime.UtcNow;

            var updated = await this.unitOfWork.Providers.UpdateAsync(provider);
            if (updated == 0)
            {
                return null;
            }

            var account = await this.unitOfWork.Accounts.FindAsync(m => m.ReferenceId == providerId && m.RoleId == (int)Roles.Provider);
            account.Active = true;

            await this.unitOfWork.Accounts.UpdateAsync(account);

            return new ProviderModel
            {
                FullName = provider.FullName,
                Salutation = provider.Salutation,
                Mobile = provider.Mobile,
                CountryId = provider.CountryId
            };
        }

        /// <inheritdoc />
        public async Task<ProviderModel> RejectAsync(int providerId, string rejectedComments)
        {
            var provider = await this.unitOfWork.Providers.FindAsync(m => m.ProviderId == providerId);
            provider.ApprovalStatus = false;
            provider.Active = false;
            provider.RejectedComments = rejectedComments;
            provider.RejectedDate = DateTime.UtcNow;

            var updated = await this.unitOfWork.Providers.UpdateAsync(provider);
            if (updated == 0)
            {
                return null;
            }

            var account = await this.unitOfWork.Accounts.FindAsync(m => m.ReferenceId == providerId && m.RoleId == (int)Roles.Provider);
            account.Active = false;
            await this.unitOfWork.Accounts.UpdateAsync(account);

            return new ProviderModel
            {
                FullName = provider.FullName,
                Salutation = provider.Salutation,
                Mobile = provider.Mobile,
                CountryId = provider.CountryId
            };
        }

        /// <inheritdoc />
        //public Task<ProviderModel> FindAsync(int providerId, int? locationId, int? specializationId)
        //{
        //    var where = $@" WHERE prv.""ProviderId"" = {providerId}";
        //    if (locationId != null)
        //    {
        //        where += $@" and PRL.""LocationId"" = {locationId}";
        //    }
        //    if (specializationId != null && specializationId != 0)
        //    {
        //        where += $@" and spl.""SpecializationId"" = {specializationId}";
        //    }

        //    var query = $@"SELECT prv.""ProviderId"",prv.""SalutationId"",sa.""Name"" as ""SalutationName"", spl.""SpecializationId"",prv.""FirstName"", prv.""MiddleName"",PL.""IsTelemedicine"",PL.""IsOnlineConsultation"", prv.""LastName"", prv.""FullName"", prv.""Gender"", prv.""MaritalStatus"", prv.""DateOfBirth"", prv.""Age"", prv.""Experience"", prv.""NPI"", prv.""PrescriberNo"", prv.""ProviderNo"", prv.""HealthIdentifierNo"", prv.""Email"", prv.""Mobile"", prv.""CountryId"", prv.""ProfileImageUrl"", prv.""ThumbnailUrl"", prv.""Active"", prv.""CreatedBy"", prv.""CreatedDate"", prv.""ModifiedBy"", prv.""ModifiedDate"", prv.""ApprovalStatus"", prv.""ApprovedDate"", prv.""RejectedComments"", prv.""RejectedDate"", prv.""Salutation"", prv.""FriendlyName"", prv.""Guid"", prv.""Theme"", prv.""EnableEmailAlerts"", prv.""EnableSMSAlerts"", prv.""EnableDesktopNotifications"", prv.""EnableMobileNotifications"", prv.""Services"" :: TEXT, prv.""Specializations"" :: TEXT, prv.""About"", prv.""Rating"", prv.""AwardsHonors"", prv.""Educations"", prv.""Memberships"", prv.""Registrations"", prv.""Experiences"", PRL.""Name"" as ""Value"",  PC.""FullName"" AS ""OptionalText"" , cun.""CountryName"", cun.""CountryCode"", cun.""ISOCode"",
        //                        cra.""FullName"" AS ""CreatedByName"", mdf.""FullName"" AS ""ModifiedByName"", PL.""Availability"", PL.""AvailableDays"", prv.""AddressLine"", prv.""City"", prv.""State"", prv.""ZipCode"",act.""UserName"",
        //                        (CASE WHEN prv.""Signature"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', prv.""Guid"", '/', prv.""Signature"") ELSE NULL END) AS ""Signature"",
        //                        (CASE WHEN prv.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', prv.""Guid"", '/', prv.""ProfileImageUrl"") ELSE NULL END) AS ""ProfileImageUrl"",
        //                        (CASE WHEN prv.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', prv.""Guid"", '/', prv.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl"",
        //                        string_agg(DISTINCT srv.""ServiceName"", ',') AS ""ServiceNames"", string_agg(DISTINCT spl.""SpecializationName"", ',') AS ""SpecializationNames"", prv.""Languages"", PB.""Percentage"", prv.""DepartmentId"",
        //                        (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 ""Provider"" prv
        //                        join ""Account"" act on act.""ReferenceId"" = prv.""ProviderId"" and act.""RoleId"" = '{(int)Roles.Provider}'
        //                        LEFT JOIN ""Country"" cun ON cun.""CountryId"" = prv.""CountryId"" AND cun.""Active"" IS TRUE
        //                        LEFT JOIN ""Account"" cra ON cra.""AccountId"" = prv.""CreatedBy"" AND cra.""Active"" IS TRUE
        //                        LEFT JOIN ""Service"" srv ON srv.""ServiceId"" = ANY(prv.""Services"") AND srv.""Active"" IS TRUE
        //                        LEFT JOIN ""ProviderLocation"" PL on PL.""ProviderId"" = prv.""ProviderId"" AND PL.""Active"" IS TRUE
        //                        LEFT JOIN ""ProviderBankAccount"" PB on PB.""ProviderId"" = prv.""ProviderId"" AND PB.""Active"" IS TRUE
        //                        LEFT JOIN ""Specialization"" spl ON spl.""SpecializationId"" = ANY(prv.""Specializations"") AND spl.""Active"" IS TRUE
        //                        LEFT JOIN ""Account"" mdf ON mdf.""AccountId"" = prv.""ModifiedBy"" AND mdf.""Active"" IS TRUE 
        //                         left join ""ProviderLocation"" PRLO on PRLO.""ProviderId"" = prv.""ProviderId""
        //                        left JOIN ""Location"" PRL on PRL.""LocationId"" = PRLO.""LocationId""
        //left JOIN ""Practice"" PC on PC.""PracticeId"" = PRL.""PracticeId""     
        //                        left Join ""Salutation"" sa on sa.""SalutationId"" = prv.""SalutationId""
        //                         {where}
        //                        GROUP BY prv.""ProviderId"",sa.""Name"",spl.""SpecializationId"", prv.""FirstName"", prv.""MiddleName"",PL.""IsTelemedicine"",PL.""IsOnlineConsultation"", prv.""LastName"", prv.""FullName"", prv.""Gender"", prv.""MaritalStatus"", prv.""DateOfBirth"", prv.""Age"", prv.""Experience"", prv.""NPI"", prv.""PrescriberNo"", prv.""ProviderNo"", prv.""HealthIdentifierNo"", prv.""Email"", prv.""Mobile"", prv.""CountryId"", prv.""ProfileImageUrl"", prv.""ThumbnailUrl"", prv.""Active"", prv.""CreatedBy"", prv.""CreatedDate"", prv.""ModifiedBy"", prv.""ModifiedDate"", prv.""ApprovalStatus"", prv.""ApprovedDate"", prv.""RejectedComments"", prv.""RejectedDate"", prv.""Salutation"", prv.""FriendlyName"", prv.""Guid"", prv.""Theme"", prv.""EnableEmailAlerts"", prv.""EnableSMSAlerts"", prv.""EnableDesktopNotifications"", prv.""EnableMobileNotifications"", prv.""Services"", prv.""Specializations"", prv.""About"", prv.""Rating"", prv.""AwardsHonors"", prv.""Educations"", prv.""Memberships"", prv.""Registrations"", prv.""Experiences"", cun.""CountryName"", cun.""CountryCode"", cun.""ISOCode"",
        //                        cra.""FullName"", mdf.""FullName"", prv.""ProfileImageUrl"", prv.""ThumbnailUrl"", PL.""Availability"", PL.""AvailableDays"", prv.""Languages"", prv.""AddressLine"", prv.""City"", prv.""State"", prv.""ZipCode"",prv.""Signature"", PB.""Percentage"", PRL.""Name"", PC.""FullName"",act.""AccountId"" limit 1";
        //    return this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderModel>(query);
        //}

        /// <inheritdoc />
        public Task<ProviderModel> FindAsync(int providerId, int? locationId, int? specializationId)
        {
            var where = $@" WHERE prv.""ProviderId"" = {providerId}";
            if (locationId != null)
            {
                where += $@" and PAL.""LocationId"" = {locationId}";
            }
            if (specializationId != null && specializationId != 0)
            {
                where += $@" and PA.""SpecializationId"" = {specializationId}";
            }

            var query = $@"SELECT prv.""ProviderId"",PA.""ProviderAvailabilityId"",prv.""SalutationId"",sa.""Name"" as ""SalutationName"", prv.""FirstName"", prv.""MiddleName""
                            --,PL.""IsTelemedicine"",PL.""IsOnlineConsultation""
                            ,PA.""ConsultationTypeId"",PA.""ProviderAvailabilityId"",PAL.""LocationId"",PL.""TelemedicineDuration"",
                            PL.""ConsultationCharges"",PL.""ConsultationDuration""
							,(Select ""StartDate"" From ""ProviderAvailability""
                                     Where ""ProviderId"" = prv.""ProviderId"" and ""LocationId"" = PAL.""LocationId""
                                     and ""SpecializationId"" = PA.""SpecializationId""
                                     and coalesce(""StartDate"",'') <> ''
                                     order by ""StartDate""::date limit 1) as ""StartDate"",
                                    (Select ""EndDate"" From ""ProviderAvailability""
                                     Where ""ProviderId"" = prv.""ProviderId"" and ""LocationId"" = PAL.""LocationId""
                                     and ""SpecializationId"" = PA.""SpecializationId""
                                     and coalesce(""StartDate"",'') <> ''
                                     order by ""EndDate""::date desc limit 1) as ""EndDate""
							--,PA.""StartDate"",PA.""EndDate""
                            ,PA.""AvailableDay"",PA.""StartTime"",PA.""EndTime""
                            --, PA.""FreeFollowUpDays"", PA.""FreeFollowUpDaysLimit""
                            , prv.""LastName"", prv.""FullName"", prv.""Gender"", prv.""MaritalStatus"", prv.""DateOfBirth"", prv.""Age"", 
                            prv.""Experience"", prv.""NPI"", prv.""PrescriberNo"", prv.""ProviderNo"", prv.""HealthIdentifierNo"", prv.""Email"",
                            prv.""Mobile"", prv.""CountryId"", prv.""Active"", prv.""CreatedBy"",
                            prv.""CreatedDate"", prv.""ModifiedBy"", prv.""ModifiedDate"", prv.""ApprovalStatus"", prv.""ApprovedDate"",
                            prv.""RejectedComments"", prv.""RejectedDate"", prv.""Salutation"", prv.""FriendlyName"", 
                            prv.""Guid"", prv.""Theme"", prv.""EnableEmailAlerts"", prv.""EnableSMSAlerts"",
                            prv.""EnableDesktopNotifications"", prv.""EnableMobileNotifications"", 
                            prv.""Services"" :: TEXT, prv.""Specializations"" :: TEXT, prv.""About"", prv.""Rating"",
                            prv.""AwardsHonors"", prv.""Educations"", prv.""Memberships"", prv.""Registrations"", prv.""Experiences"", 
                            prv.""PanCardNo"", prv.""Employee"", prv.""Type"", prv.""DoctorType""
                            , PAL.""Name"" as ""Value""
                            --,  PC.""FullName"" AS ""OptionalText"" 
                            , cun.""CountryName"", cun.""CountryCode"", cun.""ISOCode"",
                                cra.""FullName"" AS ""CreatedByName"", mdf.""FullName"" AS ""ModifiedByName""
                                --, PL.""Availability"", PL.""AvailableDays""
                                , prv.""AddressLine"", prv.""City"", prv.""State"", prv.""ZipCode"",act.""UserName"",
                                (CASE WHEN prv.""Signature"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', prv.""Guid"", '/', prv.""Signature"") ELSE NULL END) AS ""Signature"",
                                (CASE WHEN prv.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', prv.""Guid"", '/', prv.""ProfileImageUrl"") ELSE NULL END) AS ""ProfileImageUrl"",
                                (CASE WHEN prv.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', prv.""Guid"", '/', prv.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl"",
                                string_agg(DISTINCT srv.""ServiceName"", ',') AS ""ServiceNames"", string_agg(DISTINCT spl.""SpecializationName"", ',') AS ""SpecializationNames"", prv.""Languages"", PB.""Percentage"", prv.""DepartmentId"",
                                (Select  string_agg(l.""LocationId""::text, ', ') as ""LocationIdentifiers""
                                        from ""LocationAccountMap"" la
                                        join ""Location"" l ON l.""LocationId"" = la.""LocationId"" WHERE la.""AccountId"" = act.""AccountId""  and la.""Active"" is true) ,
                                        (Select  string_agg(l.""Name""::text, ', ') as ""LocationIdentifierNames""
                                        from ""LocationAccountMap"" la
                                        join ""Location"" l ON l.""LocationId"" = la.""LocationId"" WHERE la.""AccountId"" = act.""AccountId"" and la.""Active"" is true)                              
                                FROM ""Provider"" prv
                                join ""Account"" act on act.""ReferenceId"" = prv.""ProviderId"" and act.""RoleId"" = '3'
                                LEFT JOIN ""Country"" cun ON cun.""CountryId"" = prv.""CountryId"" AND cun.""Active"" IS TRUE
                                LEFT JOIN ""Account"" cra ON cra.""AccountId"" = prv.""CreatedBy"" AND cra.""Active"" IS TRUE
                                LEFT JOIN ""Service"" srv ON srv.""ServiceId"" = ANY(prv.""Services"") AND srv.""Active"" IS TRUE
                                 LEFT JOIN ""ProviderLocation"" PL on PL.""ProviderId"" = prv.""ProviderId"" AND PL.""Active"" IS TRUE
                                LEFT JOIN ""ProviderAvailability"" PA on PA.""ProviderId"" = prv.""ProviderId"" AND PA.""Active"" IS TRUE
                                left JOIN ""Location"" PAL on PAL.""LocationId"" = PA.""LocationId""
                                --left join ""ProviderAvailabilitySlot"" PAS on PAS.""ProviderAvailabilityId"" = PA.""ProviderAvailabilityId""
                                LEFT JOIN ""ProviderBankAccount"" PB on PB.""ProviderId"" = prv.""ProviderId"" AND PB.""Active"" IS TRUE
                                LEFT JOIN ""Specialization"" spl ON spl.""SpecializationId"" = ANY(prv.""Specializations"") AND spl.""Active"" IS TRUE
                                --LEFT JOIN ""Specialization"" spl on spl.""SpecializationId"" = PA.""SpecializationId"" and spl.""Active"" is true
                                LEFT JOIN ""Account"" mdf ON mdf.""AccountId"" = prv.""ModifiedBy"" AND mdf.""Active"" IS TRUE 
                                 --join ""ProviderLocation"" PRLO on PRLO.""ProviderId"" = prv.""ProviderId""
                                --left join ""ProviderAvailability"" PAY on PAY.""ProviderId"" = prv.""ProviderId""
                                --left JOIN ""Location"" PAL on PAL.""LocationId"" = PAY.""LocationId""
                                --left JOIN ""Location"" PRL on PRL.""LocationId"" = PRLO.""LocationId""
                                --left JOIN ""Practice"" PC on PC.""PracticeId"" = PRL.""PracticeId""     
                                left Join ""Salutation"" sa on sa.""SalutationId"" = prv.""SalutationId""
                                  {where}
                                GROUP BY prv.""ProviderId"",PA.""ProviderAvailabilityId"",sa.""Name"",PAL.""LocationId"", prv.""FirstName"", prv.""MiddleName"",PL.""TelemedicineDuration"",PL.""ConsultationCharges"",PL.""ConsultationDuration""
       							 --,PL.""IsTelemedicine"",PL.""IsOnlineConsultation""
							        ,PA.""ConsultationTypeId"",PA.""ProviderAvailabilityId"",PA.""StartDate"",PA.""EndDate""
							        ,PA.""AvailableDay"",PA.""StartTime"",PA.""EndTime""
                                    --, PA.""FreeFollowUpDays"", PA.""FreeFollowUpDaysLimit""
							        , prv.""LastName"", prv.""FullName"", prv.""Gender"", prv.""MaritalStatus"", prv.""DateOfBirth"", prv.""Age"", prv.""Experience"", prv.""NPI"", prv.""PrescriberNo"", prv.""ProviderNo"", prv.""HealthIdentifierNo"", prv.""Email"", prv.""Mobile"", prv.""CountryId"", prv.""ProfileImageUrl"", prv.""ThumbnailUrl"", prv.""Active"", prv.""CreatedBy"", prv.""CreatedDate"", prv.""ModifiedBy"", prv.""ModifiedDate"", prv.""ApprovalStatus"", prv.""ApprovedDate"", prv.""RejectedComments"", prv.""RejectedDate"", prv.""Salutation"", prv.""FriendlyName"", prv.""Guid"", prv.""Theme"", prv.""EnableEmailAlerts"", prv.""EnableSMSAlerts"", prv.""EnableDesktopNotifications"", prv.""EnableMobileNotifications"", prv.""Services"", prv.""Specializations"", prv.""About"", prv.""Rating"", prv.""AwardsHonors"", prv.""Educations"", prv.""Memberships"", prv.""Registrations"", prv.""Experiences"", cun.""CountryName"", cun.""CountryCode"", cun.""ISOCode"",
							                                cra.""FullName"", mdf.""FullName"", prv.""ProfileImageUrl"", prv.""ThumbnailUrl""
							        --, PL.""Availability"", PL.""AvailableDays""
							        , prv.""Languages"", prv.""AddressLine"", prv.""City"", prv.""State"", prv.""ZipCode"",prv.""Signature"", PB.""Percentage"", PAL.""Name""
							        --, PC.""FullName""
							        ,act.""AccountId"" limit 1";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<ProviderModel>> FetchAsync(ProviderFilterModel model)
        {
            var where = @"WHERE 1=1 ";

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

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

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

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

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

            if (model.Active != null)
            {
                where += $@" AND prv.""Active"" IS {((bool)model.Active ? "TRUE" : "FALSE")} ";
            }

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

            if (model.LocationIds != null)
            {
                where += $@" and LAM.""LocationId"" = {model.LocationIds}";
            }
            else
            {
                where += $@" and LAM.""LocationId"" = {model.LocationId}";

            }

            var query = $@"SELECT Count(*) OVER() AS ""TotalItems"",* from (Select distinct prv.""ProviderId"", prv.""Guid"", act.""AccountId"", prv.""FullName"", prv.""NPI"", prv.""CountryId"", act.""UserName"",
                                ctr.""CountryCode"", prv.""Email"", prv.""Mobile"", prv.""CreatedDate"", prv.""DateOfBirth"", prv.""Age"", prv.""Experience"", prv.""AddressLine"", prv.""City"", prv.""State"", prv.""ZipCode"",
								prv.""Gender"", prv.""ApprovalStatus"", prv.""ApprovedDate"", prv.""RejectedComments"", prv.""RejectedDate"", act.""IsLocked"",
                                CASE WHEN acs.""AccountSessionId"" IS NULL THEN FALSE ELSE TRUE END AS ""IsOnline"", PB.""Percentage""
                                ,(Select  string_agg(l.""NameLoc"", ', ') as ""LocationNames""
                                        from ""LocationAccountMap"" la
                                        join ""Location"" l ON l.""LocationId"" = la.""LocationId"" WHERE la.""AccountId"" = act.""AccountId""),
                                  (Select  string_agg(l.""LocationId""::text, ', ') as ""LocationIdentifiers""
                                        from ""LocationAccountMap"" la
                                        join ""Location"" l ON l.""LocationId"" = la.""LocationId"" WHERE la.""AccountId"" = act.""AccountId""),
                                (CASE WHEN prv.""Signature"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}',  '/',prv.""Guid"", '/', prv.""Signature"") ELSE NULL END) AS ""Signature"",
                                (CASE WHEN prv.""ProfileImageUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}',  '/',prv.""Guid"", '/', prv.""ProfileImageUrl"") ELSE NULL END) AS ""ProfileImageUrl"",
                                (CASE WHEN prv.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', prv.""Guid"", '/', prv.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl""
                                FROM ""Provider"" prv
                                JOIN ""Account"" act ON act.""ReferenceId"" = prv.""ProviderId"" AND  act.""RoleId"" = '{(int)Roles.Provider}'
                                join ""LocationAccountMap"" LAM on LAM.""AccountId"" = act.""AccountId""
                                left join ""AccountSession"" acs on acs.""AccountId"" = act.""AccountId""  AND acs.""Active"" IS TRUE                                
                                LEFT JOIN ""Country"" ctr ON ctr.""CountryId"" = prv.""CountryId"" AND ctr.""Active"" IS TRUE
                                LEFT JOIN ""ProviderBankAccount"" PB on PB.""ProviderId"" = prv.""ProviderId"" AND PB.""Active"" IS TRUE
                                {where}
                                ORDER BY ""IsOnline"" DESC) A";


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

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            var providers = await this.unitOfWork.Current.QueryAsync<ProviderModel>(query);

            return providers;
        }

        /// <inheritdoc />
        public Task<IEnumerable<ProviderListItemModel>> FetchListItemsAsync(ProviderListItemFilterModel model)
        {
            var where = $@" where PL.""IsOnlineConsultation"" is true and P.""Active"" IS TRUE AND Sz.""Active"" IS TRUE AND A.""RoleId"" = {(int)Roles.Provider} AND p.""ApprovalStatus"" IS TRUE ";
            var whereCreatedBy = string.Empty;
            if (model.PracticeId > 0)
            {
                where += $@" and Pr.""PracticeId"" = {model.PracticeId} ";
            }

            if (model.ProviderId > 0)
            {
                where += $@" and P.""ProviderId"" = {model.ProviderId} ";
            }

            //if (model.PatientId > 0)
            //{
            //    whereCreatedBy =
            //        $@" (select c.""PatientId"",c.""CreatedBy"" from  ""Patient"" c where c.""PatientId""={model.PatientId}) pat, ";
            //    where += $@" and case when pat.""CreatedBy"" = acc.""AccountId"" then 1=1
            //                          when pat.""CreatedBy"" is not null then 					 
            //  (apt.""PatientId"" = {model.PatientId} or (pat.""PatientId"" = {model.PatientId} and pat.""CreatedBy"" = A.""AccountId""))
            //                          else 1=1 end ";
            //}

            if (model.PatientId > 0)
            {
                where += $@" and pat.""PatientId"" = {model.PatientId} ";
            }


            if (model.SpecializationId > 0)
            {
                where += $@" and SZ.""SpecializationId"" = {model.SpecializationId} ";
            }

            if (model.ServiceId > 0)
            {
                where += $@" and Ser.""ServiceId"" = {model.ServiceId} ";
            }

            if (model.ProviderLocationId > 0)
            {
                where +=
                    $@" and trim(Upper(PRL.""FullName"")) in (select trim(upper(""FullName"")) from  ""PracticeLocation"" where ""PracticeLocationId""={model.ProviderLocationId})";
            }

            if (model.IsTelemedicine != null)
            {
                if (Convert.ToBoolean(model.IsTelemedicine))
                {
                    where += $@" and PL.""TelemedicineDuration"" IS NOT NULL";
                }
                else
                {
                    where += $@" and PL.""ConsultationDuration"" IS NOT NULL";
                }
            }

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

            if (!string.IsNullOrEmpty(model.SearchParam))
            {
                where += $@" and (Sz.""SpecializationName"" ilike '%{model.SearchParam}%' or Ser.""ServiceName"" ilike '%{model.SearchParam}%' or P.""FullName"" ilike '%{model.SearchParam}%' or Pr.""FullName"" ilike '%{model.SearchParam}%')";
            }
            if (model.LocationId != null)
            {
                where += $@" AND PL.""LocationId"" = '{model.LocationId}' ";
            }

            var query =
                $@" SELECT count(P.*) over() as ""TotalItems"" , Sz.""SpecializationId"",A.""AccountId"", P.""ProviderId"", P.""FullName"" as ""ProviderName"", P.""Experience"", P.""Gender"", P.""Languages"",
                                PL.""ProviderLocationId"",PL.""IsTelemedicine"",PL.""IsOnlineConsultation"", PL.""ConsultationDuration"", PL.""ConsultationCharges"", PL.""TelemedicineCharges"", PL.""TelemedicineDuration"",
                                Pr.""FullName"" as ""PracticeName"", CUN.""CurrencySymbol"", PL.""AvailableDays"", PL.""Availability"",
                                CONCAT(PrL.""Name"") as ""Location"", PrL.""LocationId"",
                                string_agg(DISTINCT Sz.""SpecializationName"", ',') as ""Specializations"",
                                string_agg(DISTINCT Ser.""ServiceName"", ',') as ""Services"",
                                (CASE WHEN P.""ProfileImageUrl"" IS NOT NULL and P.""ProfileImageUrl"" <> ''  THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ProfileImageUrl"") ELSE NULL END) AS ""ProfileImageUrl"",
                                (CASE WHEN P.""ThumbnailUrl"" IS NOT NULL and P.""ThumbnailUrl"" <> '' THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl""
                                from  ""Provider"" P
                                join ""Account"" A on A.""ReferenceId"" = P.""ProviderId"" and A.""RoleId"" = 3 AND A.""Active"" IS TRUE
                                join ""ProviderLocation"" PL on PL.""ProviderId"" = P.""ProviderId"" AND PL.""Active"" IS TRUE
                                join ""Location"" PrL on PrL.""LocationId"" = PL.""LocationId"" AND PrL.""Active"" IS TRUE
                                join ""Country"" CUN on CUN.""CountryId"" = P.""CountryId"" AND CUN.""Active"" IS TRUE
                                join ""Practice"" Pr on Pr.""PracticeId"" = PrL.""PracticeId"" AND Pr.""Active"" IS TRUE
                                left join ""Specialization"" Sz on Sz.""SpecializationId"" = ANY(P.""Specializations"") AND Sz.""Active"" IS TRUE
                                left join ""Service"" Ser on Ser.""ServiceId"" = ANY(P.""Services"") AND Ser.""Active"" IS TRUE
                                left join ""Appointment"" apt on  P.""ProviderId""=apt.""ProviderId""  
                     --        left join ""Account"" acc on acc.""RoleId"" = 2 AND acc.""Active"" IS TRUE
                                left join ""Patient"" pat on pat.""PatientId""=apt.""PatientId""
                                {where}
                                Group By A.""AccountId"",Sz.""SpecializationId"", P.""ProviderId"",P.""FullName"",P.""Experience"",P.""Gender"", P.""Languages"", CUN.""CurrencySymbol"",
                                PL.""ProviderLocationId"",PL.""ConsultationDuration"",PL.""ConsultationCharges"",PL.""TelemedicineCharges"",
                                PL.""TelemedicineCharges"",Pr.""FullName"",Pr.""PracticeId"",PL.""AvailableDays"",PrL.""Name"", PrL.""LocationId""
                                order by P.""ProfileImageUrl"" ASC NULLS LAST, P.""FullName"" ASC";

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

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<ProviderListItemModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(ProviderModel model)
        {
            var checkIf = await this.CheckProviderAsync(model.Mobile, model.CountryId, model.NPI, model.Email, model.ProviderId);
            if (checkIf != 0)
            {
                return checkIf;
            }

            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var provider = await this.unitOfWork.Providers.FindAsync(m => m.ProviderId == model.ProviderId);
                provider.HealthIdentifierNo = model.HealthIdentifierNo;
                provider.PrescriberNo = model.PrescriberNo;
                provider.FirstName = model.FirstName;
                provider.MiddleName = model.MiddleName;
                provider.LastName = model.LastName;
                provider.MaritalStatus = model.MaritalStatus;
                provider.FullName = CoreFilter.FullName(model.FirstName, model.MiddleName, model.LastName);
                provider.FriendlyName = model.FriendlyName;
                provider.DateOfBirth = model.DateOfBirth;
                provider.Age = model.Age;
                provider.Experience = model.Experience;
                provider.Gender = model.Gender;
                provider.Email = model.Email;
                provider.Mobile = model.Mobile;
                provider.Experience = model.Experience;
                provider.NPI = model.NPI ?? provider.NPI;
                provider.Salutation = model.Salutation;
                provider.ProviderNo = model.ProviderNo;
                provider.CountryId = model.CountryId;
                if (!string.IsNullOrEmpty(model.Base64ProfileImage))
                {
                    provider.ProfileImageUrl = model.ProfileImageUrl;
                    provider.ThumbnailUrl = model.ThumbnailUrl;
                }
                provider.About = model.About;
                provider.Theme = model.Theme;
                provider.Experiences = model.Experiences;
                provider.AwardsHonors = model.AwardsHonors;
                provider.Educations = model.Educations;
                provider.Memberships = model.Memberships;
                provider.Registrations = model.Registrations;
                provider.EnableEmailAlerts = model.EnableEmailAlerts;
                provider.EnableDesktopNotifications = model.EnableDesktopNotifications;
                provider.EnableSMSAlerts = model.EnableSMSAlerts;
                provider.EnableMobileNotifications = model.EnableMobileNotifications;
                provider.Languages = model.Languages;
                provider.AddressLine = model.AddressLine;
                provider.City = model.City ?? provider.City;
                provider.State = model.State ?? provider.State;
                provider.ZipCode = model.ZipCode ?? provider.ZipCode;
                provider.DepartmentId = model.DepartmentId ?? provider.DepartmentId;
                provider.ModifiedBy = model.ModifiedBy;
                provider.ModifiedDate = DateTime.UtcNow;
                if (!string.IsNullOrEmpty(model.Base64Signature))
                {
                    provider.Signature = model.Signature;
                }
                provider.ClinicPicture = model.ClinicPicture;

                provider.SalutationId = model.SalutationId;
                provider.PanCardNo = model.PanCardNo;
                provider.Employee = model.Employee;
                provider.Type = model.Type;
                provider.DoctorType = model.DoctorType;

                if (!string.IsNullOrEmpty(model.Specializations))
                {
                    var query = $@"UPDATE ""Provider"" SET ""Specializations"" = ARRAY[{model.Specializations}], ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'";
                    await this.unitOfWork.Current.ExecuteAsync(query);
                }

                var updated = await this.unitOfWork.Providers.UpdateAsync(provider);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Provider && m.ReferenceId == provider.ProviderId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                if (account.Email != provider.Email || account.Mobile != provider.Mobile || account.CountryId != provider.CountryId || account.FullName != provider.FullName + " (" + provider.FriendlyName + ")" || account.UserName != model.UserName)
                {
                    account.Email = provider.Email;
                    account.Mobile = provider.Mobile;
                    account.CountryId = provider.CountryId;
                    account.UserName = model.UserName;
                    account.FullName = provider.FullName + " (" + provider.FriendlyName + ")";
                    updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                    if (updated == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }

                try
                {
                    var selectQuery = await this.unitOfWork.LocationAccountMap.FindAllAsync(m => m.AccountId == account.AccountId);
                    if (selectQuery.Count() == 0)
                    {
                        transaction.Rollback();
                        return 0;
                    }

                    
                    List<int> locationIds = new List<int>(model.LocationIds);

                    // making false of a locationId which is true
                    var missingLocations = selectQuery.Where(
                        location => !locationIds.Contains(location.LocationId)
                    ).ToList();

                    foreach (var location in missingLocations)
                    {
                        location.Active = false;
                        location.ModifiedBy = account.AccountId;
                        location.ModifiedDate = DateTime.Now;
                        var locationUpdatedId = await this.unitOfWork.LocationAccountMap.UpdateAsync(location, transaction);
                        if (locationUpdatedId == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }

                        var checkInLocationUpdate = await this.unitOfWork.ProviderAvailability.FindAsync(p => p.ProviderId == provider.ProviderId && p.LocationId == location.LocationId);

                        if (checkInLocationUpdate != null)
                        {
                            checkInLocationUpdate.Active = false;
                            checkInLocationUpdate.ModifiedBy = account.AccountId;
                            checkInLocationUpdate.ModifiedDate = DateTime.Now;

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

                    //making as active which are false
                    var addedMissingLocationIds = locationIds.Where(
                                       locationId => selectQuery.Any(location => location.LocationId == locationId && location.Active == false)
                                   ).ToList();

                    // finding lcoation account map account id with locationId which is false
                    var findLocationAccountMapIds = selectQuery.Where(
                        location => addedMissingLocationIds.Contains(location.LocationId)
                    ).ToList();

                    foreach (var Addedlocation in findLocationAccountMapIds)
                    {
                        Addedlocation.Active = true;
                        Addedlocation.ModifiedBy = account.AccountId;
                        Addedlocation.ModifiedDate = DateTime.Now;
                        var locationUpdatedId = await this.unitOfWork.LocationAccountMap.UpdateAsync(Addedlocation, transaction);
                        if (locationUpdatedId == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }

                        var AddedLocationUpdate = await this.unitOfWork.ProviderAvailability.FindAsync(p => p.ProviderId == provider.ProviderId && p.LocationId == Addedlocation.LocationId);

                        if (AddedLocationUpdate != null)
                        {
                            AddedLocationUpdate.Active = true;
                            AddedLocationUpdate.ModifiedBy = account.AccountId;
                            AddedLocationUpdate.ModifiedDate = DateTime.Now;

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

                    var addedNewLocationIds = locationIds.Where(
                                       locationId => !selectQuery.Any(location => location.LocationId == locationId)
                                   ).ToList();

                    // Output the missing locationIds
                    foreach (var locationId in addedNewLocationIds)
                    {
                        var location = new LocationAccountMap
                        {
                            AccountId = account.AccountId,
                            LocationId = locationId
                        };
                        var locationInsertId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);

                        if (locationInsertId == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }

                        var checkInLocation = await this.unitOfWork.ProviderAvailability.FindAsync(p => p.ProviderId == provider.ProviderId && p.LocationId == locationId);

                        if (checkInLocation == null)
                        {
                            var providerLocationModel = new ProviderAvailability
                            {
                                LocationId = locationId,
                                Active = true,
                                CreatedBy = account.AccountId,
                                CreatedDate = DateTime.Now,
                                ProviderId = provider.ProviderId
                            };

                            var id = await this.unitOfWork.ProviderAvailability.InsertAsync(providerLocationModel, transaction);
                            if (id == 0)
                            {
                                transaction.Rollback();
                                return 0;
                            }
                        }
                        //Console.WriteLine($"Missing locationId: {locationId}");
                    }
                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    return -1;
                }
                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<Tuple<int, int, Guid?>> AddAsync(ProviderModel model)
        {
            try
            {
                var checkIf = await this.CheckProviderAsync(model.Mobile, model.CountryId, model.NPI, model.Email, model.ProviderId);
                if (checkIf != 0)
                {
                    //return new Tuple<int, Guid?>(0, null);
                    return new Tuple<int, int, Guid?>(0, checkIf, null);
                }

                using var transaction = this.unitOfWork.BeginTransaction();
                var provider = new Provider
                {
                    FirstName = model.FirstName,
                    MiddleName = model.MiddleName,
                    //MaritalStatus = model.MaritalStatus,
                    LastName = model.LastName,
                    FullName = CoreFilter.FullName(model.FirstName, model.MiddleName, model.LastName),
                    FriendlyName = model.FriendlyName,
                    //DateOfBirth = model.DateOfBirth,
                    Age = model.Age,
                    Experience = model.Experience,
                    Gender = model.Gender,
                    Email = model.Email,
                    Mobile = model.Mobile,
                    NPI = model.NPI,
                    CountryId = model.CountryId,
                    //ProfileImageUrl = model.ProfileImageUrl,
                    ThumbnailUrl = model.ThumbnailUrl,
                    //Theme = model.Theme,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow,
                    ApprovalStatus = true,
                    Active = true,
                    EnableEmailAlerts = model.EnableEmailAlerts,
                    EnableDesktopNotifications = model.EnableDesktopNotifications,
                    EnableMobileNotifications = model.EnableMobileNotifications,
                    Languages = model.Languages,
                    EnableSMSAlerts = model.EnableSMSAlerts,
                    ProviderNo = model.ProviderNo,
                    About = model.About,
                    HealthIdentifierNo = model.HealthIdentifierNo,
                    PrescriberNo = model.PrescriberNo,
                    Experiences = model.Experiences,
                    AwardsHonors = model.AwardsHonors,
                    Educations = model.Educations,
                    Memberships = model.Memberships,
                    Registrations = model.Registrations,
                    AddressLine = model.AddressLine,
                    City = model.City,
                    State = model.State,
                    ZipCode = model.ZipCode,
                    Specializations = model.Specializations.ToArray(),
                    DepartmentId = Convert.ToInt32(model.DepartmentId),
                    Guid = Guid.NewGuid(),
                    SalutationId = model.SalutationId,
                    Type = model.Type,
                    DoctorType = model.DoctorType,
                    PanCardNo = model.PanCardNo,
                    Employee = model.Employee
                };

                provider.ProviderId = await this.unitOfWork.Providers.InsertAsync(provider, transaction);

                if (!string.IsNullOrEmpty(model.Specializations))
                {
                    var query = $@"UPDATE ""Provider"" SET ""Specializations"" = ARRAY[{model.Specializations}], ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{provider.ProviderId}'";
                    await this.unitOfWork.Current.ExecuteAsync(query);
                }

                if (provider.ProviderId == 0)
                {
                    transaction.Rollback();
                    //return new Tuple<int, Guid?>(0, null);
                    return new Tuple<int, int, Guid?>(0, checkIf, null);
                }

                var providerName = string.IsNullOrEmpty(provider.FriendlyName) ? provider.FullName : provider.FriendlyName;
                var saltKey = CoreFilter.Random(10);
                var existingAccount = await this.unitOfWork.Accounts.FindAsync(m => m.Email == provider.Email && m.Mobile == provider.Mobile && m.CountryId == provider.CountryId, transaction);
                if (existingAccount != null && existingAccount.AccountId != 0)
                {
                    saltKey = existingAccount.SaltKey;
                }

                var account = new Account
                {
                    RoleId = (int)Roles.Provider,
                    ReferenceId = provider.ProviderId,
                    SaltKey = saltKey,
                    CreatedDate = DateTime.Now,
                    Email = provider.Email,
                    Mobile = provider.Mobile,
                    CountryId = provider.CountryId,
                    FullName = providerName,
                    Active = true,
                    Guid = provider.Guid,
                    UserName = model.UserName
                };

                account.AccountId = await this.unitOfWork.Accounts.InsertAsync(account, transaction);
                if (account.AccountId == 0)
                {
                    transaction.Rollback();
                    //return new Tuple<int, Guid?>(0, null);
                    return new Tuple<int, int, Guid?>(0, checkIf, null);
                }

                foreach (var locationId in model.LocationIds)
                {
                    var location = new LocationAccountMap
                    {
                        AccountId = account.AccountId,
                        LocationId = locationId,
                        Active = true,
                        CreatedBy = account.AccountId,
                        CreatedDate = DateTime.Now
                    };
                    var locationInsertId = await this.unitOfWork.LocationAccountMap.InsertAsync(location, transaction);
                    if (locationInsertId == 0)
                    {
                        transaction.Rollback();
                        //return new Tuple<int, Guid?>(0, null);
                        return new Tuple<int, int, Guid?>(0, checkIf, null);
                    }

                    //var checkInLocation = await this.unitOfWork.ProviderLocations.FindAsync(p => p.ProviderId == provider.ProviderId && p.LocationId == locationId);

                    var checkInLocation = await this.unitOfWork.ProviderAvailability.FindAsync(p => p.ProviderId == provider.ProviderId && p.LocationId == locationId);
                    try
                    {
                        if (checkInLocation == null)
                        {
                            var providerAvailabilityModel = new ProviderAvailability
                            {
                                LocationId = locationId,
                                Active = true,
                                CreatedBy = account.AccountId,
                                CreatedDate = DateTime.Now,
                                ProviderId = provider.ProviderId
                            };

                            var id = await this.unitOfWork.ProviderAvailability.InsertAsync(providerAvailabilityModel, transaction);
                            if (id == 0)
                            {
                                transaction.Rollback();
                                //return new Tuple<int, Guid?>(0, null);
                                return new Tuple<int, int, Guid?>(0, checkIf, null);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.Message.ToString();
                    }


                    //if (checkInLocation == null)
                    //{
                    //    var providerLocationModel = new ProviderLocation
                    //    {
                    //        LocationId = locationId,
                    //        Active = true,
                    //        CreatedBy = account.AccountId,
                    //        CreatedDate = DateTime.Now,
                    //        ProviderId = provider.ProviderId
                    //    };

                    //    var id = await this.unitOfWork.ProviderLocations.InsertAsync(providerLocationModel, transaction);
                    //    if (id == 0)
                    //    {
                    //        transaction.Rollback();
                    //        return new Tuple<int, Guid?>(0, null);
                    //    }
                    //}
                }

                transaction.Commit();
                if (!string.IsNullOrEmpty(model.Specializations))
                {
                    var query1 = $@"UPDATE ""Provider"" SET ""Specializations"" = ARRAY[{model.Specializations}] WHERE ""ProviderId""= '{provider.ProviderId}'";
                    await this.unitOfWork.Current.ExecuteAsync(query1);
                }

                if (!string.IsNullOrEmpty(model.Services))
                {
                    var query1 = $@"UPDATE ""Provider"" SET ""Services"" = ARRAY[{model.Services}] WHERE ""ProviderId""= '{provider.ProviderId}'";
                    await this.unitOfWork.Current.ExecuteAsync(query1);
                }

                //return new Tuple<int, Guid?>(account.AccountId, account.Guid);
                return new Tuple<int, int, Guid?>(account.AccountId, provider.ProviderId, account.Guid);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        /// <inheritdoc />
        public Task<int> DeleteAsync(int providerId)
        {
            var query = $@"DELETE FROM ""Provider"" WHERE ""ProviderId""= '{providerId}'; DELETE FROM ""Account"" WHERE ""ReferenceId""= '{providerId}' AND """" = '{(int)Roles.Provider}';";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateProfileAsync(ModifyProviderProfileModel model)
        {
            string query = model.ProfileType switch
            {
                ProviderProfileType.Specializations => $@"UPDATE ""Provider"" SET ""Specializations"" = ARRAY[{model.Value}], ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Services => $@"UPDATE ""Provider"" SET ""Services"" = ARRAY[{model.Value}], ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Experiences => $@"UPDATE ""Provider"" SET ""Experiences"" = '{model.Value}', ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Educations => $@"UPDATE ""Provider"" SET ""Educations"" = '{model.Value}', ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Awards => $@"UPDATE ""Provider"" SET ""AwardsHonors"" = '{model.Value}', ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Memberships => $@"UPDATE ""Provider"" SET ""Memberships"" = '{model.Value}', ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                ProviderProfileType.Registrations => $@"UPDATE ""Provider"" SET ""Registrations"" = '{model.Value}', ""ModifiedBy"" = {model.ModifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderId""= '{model.ProviderId}'",
                _ => string.Empty,
            };
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateSignatureUrlsAsync(string signature, string logo, Guid guid)
        {
            var query = $@"UPDATE ""Provider"" SET ""Signature"" = '{signature}', ""ClinicPicture"" = '{logo}' WHERE ""Guid""= '{guid}'";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateProfileImageUrlsAsync(string profileImageUrl, string thumbnailUrl, Guid guid)
        {
            var query = $@"UPDATE ""Provider"" SET ""ProfileImageUrl"" = '{profileImageUrl}', ""ThumbnailUrl"" = '{thumbnailUrl}' WHERE ""Guid""= '{guid}'";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateImageUrlsAsync(ProviderModel model, Guid guid)
        {
            var query = $@"UPDATE ""Provider"" SET ""ProfileImageUrl"" = '{model.ProfileImageUrl}', ""ThumbnailUrl"" = '{model.ThumbnailUrl}' WHERE ""Guid""= '{guid}'";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> UpdateThumbnailImageUrlsAsync(string profileImageUrl, string thumbnailUrl, Guid guid)
        {
            var query = $@"UPDATE ""Provider"" SET ""ProfileImageUrl"" = '{profileImageUrl}', ""ThumbnailUrl"" = '{thumbnailUrl}' WHERE ""Guid""= '{guid}'";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<int> CheckProviderAsync(string mobile, int? countryId, string npi, string email, int providerId)
        {
            int checkIf;
            if (!string.IsNullOrEmpty(email))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE TRIM(UPPER(""Email"")) = '{email.ToUpper().Trim()}' AND  ""ProviderId"" <> '{providerId}'");
                if (checkIf > 0)
                {
                    return -1;
                }

                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE TRIM(UPPER(""Email"")) = '{email.ToUpper().Trim()}' AND ""RoleId"" IN ({(int)Roles.Nurse},{(int)Roles.Receptionist}) ");
                if (checkIf > 0)
                {
                    return -1;
                }
            }

            if (!string.IsNullOrEmpty(mobile) && countryId != null)
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE ""Mobile"" = '{mobile}' AND  ""CountryId"" = '{countryId}' AND  ""ProviderId"" <> '{providerId}'");
                if (checkIf > 0)
                {
                    return -2;
                }

                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""UserId"") FROM ""User"" WHERE ""Mobile"" = '{mobile}' AND  ""CountryId"" = '{countryId}' AND ""RoleId"" IN ({(int)Roles.Nurse},{(int)Roles.Receptionist}) ");
                if (checkIf > 0)
                {
                    return -2;
                }
            }

            if (!string.IsNullOrEmpty(npi))
            {
                checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderId"") FROM ""Provider"" WHERE ""NPI"" = '{npi}' AND  ""ProviderId"" <> '{providerId}'");
                if (checkIf > 0)
                {
                    return -3;
                }
            }

            return 0;
        }

        /// <inheritdoc />
        public async Task<int> LockedStatusAsync(ProviderModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                // Patient's Account
                var account = await this.unitOfWork.Accounts.FindAsync(m => m.RoleId == (int)Roles.Provider && m.ReferenceId == model.ProviderId, transaction);
                if (account == null || account.AccountId == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                account.IsLocked = Convert.ToBoolean(model.IsLocked);
                account.ModifiedBy = model.ModifiedBy;
                account.ModifiedDate = DateTime.UtcNow;

                var updated = await this.unitOfWork.Accounts.UpdateAsync(account, transaction);
                if (updated == 0)
                {
                    transaction.Rollback();
                    return 0;
                }

                transaction.Commit();
                return updated;
            }
        }

        /// <inheritdoc />
        public async Task<IEnumerable<ProviderListItemModel>> ProviderList(ProviderListItemFilterModel model)
        {
            var where = $@" where P.""Active"" IS TRUE AND P.""ApprovalStatus"" IS TRUE ";
            var whereCreatedBy = string.Empty;
            if (model.PracticeId > 0)
            {
                where += $@" and Pr.""PracticeId"" = {model.PracticeId} ";
            }

            if (model.ProviderId > 0)
            {
                where += $@" and P.""ProviderId"" = {model.ProviderId} ";
            }

            if (model.IsTelemedicine != null)
            {
                if (Convert.ToBoolean(model.IsTelemedicine))
                {
                    where += $@" and PL.""TelemedicineDuration"" IS NOT NULL";
                }
                else
                {
                    where += $@" and PL.""ConsultationDuration"" IS NOT NULL";
                }
            }

            //if (model.PatientId > 0)
            //{
            //    whereCreatedBy =
            //        $@" (select c.""PatientId"",c.""CreatedBy"" from  ""Patient"" c where c.""PatientId""={model.PatientId}) pat, ";
            //    where += $@" and case when pat.""CreatedBy"" = acc.""AccountId"" then 1=1
            //                          when pat.""CreatedBy"" is not null then 					 
            //  (apt.""PatientId"" = {model.PatientId} or (pat.""PatientId"" = {model.PatientId} and pat.""CreatedBy"" = A.""AccountId""))
            //                          else 1=1 end ";
            //}

            if (model.SpecializationId > 0)
            {
                where += $@" and SZ.""SpecializationId"" = {model.SpecializationId} ";
            }

            if (model.ServiceId > 0)
            {
                where += $@" and Ser.""ServiceId"" = {model.ServiceId} ";
            }

            if (!string.IsNullOrEmpty(model.SearchParam))
            {
                where += $@" and (Sz.""SpecializationName"" ilike '%{model.SearchParam}%' or Ser.""ServiceName"" ilike '%{model.SearchParam}%' or P.""FullName"" ilike '%{model.SearchParam}%' or Pr.""FullName"" ilike '%{model.SearchParam}%')";
            }

            var query = $@"Select count(P.*) over() as ""TotalItems"" , A.""AccountId"", P.""ProviderId"",P.""FullName"" as ""ProviderName"",P.""Experience"",P.""Languages"",
                                    PrL.""Name"" as ""Location"",PL.""AvailableDays"", PL.""Availability"", PL.""ConsultationDuration"",PL.""TelemedicineDuration"",
                                    string_agg(DISTINCT Sz.""SpecializationName"", ',') as ""Specializations"",
                                    string_agg(DISTINCT Ser.""ServiceName"", ',') as ""Services"",Pr.""FullName"" as ""PracticeName"",
                                    (CASE WHEN P.""ProfileImageUrl"" IS NOT NULL and P.""ProfileImageUrl"" <> ''  THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ProfileImageUrl"") ELSE NULL END) AS ""ProfileImageUrl"",
                                    (CASE WHEN P.""ThumbnailUrl"" IS NOT NULL and P.""ThumbnailUrl"" <> '' THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl""
                                    from {whereCreatedBy} ""Provider"" P
                                    join ""Account"" A on A.""ReferenceId"" = P.""ProviderId"" and A.""RoleId"" = 3 AND A.""Active"" IS TRUE
                                    join ""ProviderLocation"" PL on PL.""ProviderId"" = P.""ProviderId"" AND PL.""Active"" IS TRUE
                                    join ""Location"" PrL on PrL.""LocationId"" = PL.""LocationId"" AND PrL.""Active"" IS TRUE
                                    join ""Practice"" Pr on Pr.""PracticeId"" = PrL.""PracticeId"" AND Pr.""Active"" IS TRUE
                                    left join ""Specialization"" Sz on Sz.""SpecializationId"" = ANY(P.""Specializations"") AND Sz.""Active"" IS TRUE
                                    left join ""Service"" Ser on Ser.""ServiceId"" = ANY(P.""Services"") AND Ser.""Active"" IS TRUE
                                    left join ""Appointment"" apt on  P.""ProviderId""=apt.""ProviderId""  
                                    left join ""Account"" acc on acc.""RoleId"" = 2 AND acc.""Active"" IS TRUE
                                    {where}
                                    group by P.""FullName"",A.""AccountId"",P.""Experience"",Pr.""FullName"",P.""ProviderId"",P.""Languages"",PrL.""Name"",PL.""AvailableDays"", PL.""Availability"",PL.""ConsultationDuration"",PL.""TelemedicineDuration""
                                    order by P.""ProfileImageUrl"" ASC NULLS LAST, P.""FullName"" ASC";
            if (model.PageIndex <= 0)
            {
                return await this.unitOfWork.Current.QueryAsync<ProviderListItemModel>(query);
            }

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return await this.unitOfWork.Current.QueryAsync<ProviderListItemModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<ProviderListItemModel>> GetProviderAvailabilityAsync(string providerIds, int? providerLocationId)
        {
            var where = $@"";
            if (providerLocationId != null && providerLocationId > 0)
            {
                where += $@"and PL.""ProviderLocationId"" = {providerLocationId} ";
            }
            var query = $@"SELECT  PL.""ProviderId"" ,PL.""Availability"",C.""Currency"",C.""CurrencySymbol"", PL.""ProviderLocationId"",PrL.""LocationId""

                                FROM ""ProviderLocation"" PL join ""Location"" PrL on PrL.""LocationId"" = PL.""LocationId""
                                JOIN ""Practice"" pra ON pra.""PracticeId"" = prl.""PracticeId"" AND pra.""Active"" IS TRUE
	                            JOIN ""Country"" C on C.""CountryId""=PrL.""CountryId"" where PL.""ProviderId"" in ({providerIds})  {where} AND PL.""Active"" IS TRUE ";
            return await this.unitOfWork.Current.QueryAsync<ProviderListItemModel>(query);
        }

        /// <inheritdoc />
        public int FindProviderIdByAsync(string email, string mobile)
        {
            var query_ = $@"Select ""ProviderId"" from ""Provider"" where ""Email"" = '{email}' or ""Mobile"" = '{mobile}'";
            var res = this.unitOfWork.Current.ExecuteScalar<int>(query_);
            return res;
        }

        /// <inheritdoc />
        public async Task<ProviderModel> FindProviderByProviderId(int providerId)
        {
            try
            {
                var data = await this.unitOfWork.Providers.FindAsync(m => m.ProviderId == providerId);
                return new ProviderModel
                {
                    ProviderId = data.ProviderId,
                    FullName = data.FullName,

                };
            }
            catch (Exception e)
            {
                throw;
            }

        }

        public async Task<int> FindLocationIdByProviderLocationId(int providerLocationId)
        {
            var query = $@"SELECT ""LocationId"" FROM ""ProviderLocation"" WHERE ""ProviderLocationId"" = {providerLocationId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return response;
        }

        public async Task<string> FindProviderByAdmissionId(int admissionId)
        {
            var query = $@"SELECT ""FullName"" FROM ""Provider"" pr WHERE pr.""ProviderId"" = (SELECT ""ProviderId"" FROM ""Admission"" a WHERE a.""AdmissionId"" = {admissionId})";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        /// <inheritdoc />
        public async Task<int> AddProviderConsultationRoom(ProviderConsultationRoomModel model)
        {
            var checkIf = await this.unitOfWork.ProviderConsultationRooms.FindAsync(m => m.ProviderId == model.ProviderId && m.LocationId == model.LocationId);
            if (checkIf != null && model.ProviderConsultationRoomId == 0)
            {
                return -1;
            }

            if (model.ProviderConsultationRoomId > 0)
            {
                checkIf.RoomId = model.RoomId;
                return await this.unitOfWork.ProviderConsultationRooms.UpdateAsync(checkIf);
            }

            var provider = new ProviderConsultationRoom
            {
                RoomId = model.RoomId,
                LocationId = model.LocationId,
                ProviderId = model.ProviderId
            };

            return await this.unitOfWork.ProviderConsultationRooms.InsertAsync(provider);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<BedManagementModel>> FetchProvidersRoom(ProviderConsultationRoomModel model)
        {
            var where = "where 1=1";
            if (model.ProviderId > 0)
            {
                where += $@" and PCR.""ProviderId"" = {model.ProviderId}";
            }

            if (model.LocationId > 0)
            {
                where += $@" and PCR.""LocationId"" = {model.LocationId}";
            }

            var query = $@"SELECT w.""WardName"",  w.""WardId"",  r.""RoomName"",r.""RoomId"" ,f.""FloorName"" , f.""FloorId"",
	                                PCR.""ProviderId"",PCR.""ProviderConsultationRoomId""
                                       from ""Ward"" w             
                                       join ""Room"" r on r.""WardId"" = w.""WardId""                        
                                       join ""Floor"" f on f.""FloorId"" = w.""FloorId""
                                       join ""ProviderConsultationRoom"" PCR on PCR.""RoomId""= r.""RoomId"" 
                                        {where}";
            return await this.unitOfWork.Current.QueryAsync<BedManagementModel>(query);
        }


        /// <inheritdoc />
        public Task<IEnumerable<ProviderSpecializationModel>> FetchDoctorSpecializationAsync(ProviderSpecializationModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += model.LocationId != null ? $@",{model.LocationId}" : ",null";
            parameters += model.ConsultationTypeId != null ? $@",{model.ConsultationTypeId}" : ",null";

            var query = $@"select * from ""udf_FetchDoctor_With_Availability_Specialization""({parameters})";

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

        /// <inheritdoc />
        public Task<IEnumerable<ProviderListItemModel>> FetchProviderListItemsAsync(ProviderListItemFilterModel model)
        {
            var where = $@" where CT.""Active"" is true and P.""Active"" IS TRUE AND Sz.""Active"" IS TRUE AND A.""RoleId"" = {(int)Roles.Provider} AND p.""ApprovalStatus"" IS TRUE AND

                                PA.""EndDate""::Date >= now()::Date";

            var whereCreatedBy = string.Empty;
            if (model.PracticeId > 0)
            {
                where += $@" and Pr.""PracticeId"" = {model.PracticeId} ";
            }

            if (model.ProviderId > 0)
            {
                where += $@" and P.""ProviderId"" = {model.ProviderId} ";
            }

            //if (model.PatientId > 0)
            //{
            //    whereCreatedBy =
            //        $@" (select c.""PatientId"",c.""CreatedBy"" from  ""Patient"" c where c.""PatientId""={model.PatientId}) pat, ";
            //    where += $@" and case when pat.""CreatedBy"" = acc.""AccountId"" then 1=1
            //                          when pat.""CreatedBy"" is not null then 					 
            //  (apt.""PatientId"" = {model.PatientId} or (pat.""PatientId"" = {model.PatientId} and pat.""CreatedBy"" = A.""AccountId""))
            //                          else 1=1 end ";
            //}

            if (model.PatientId > 0)
            {
                where += $@" and pat.""PatientId"" = {model.PatientId} ";
            }


            if (model.SpecializationId > 0)
            {
                where += $@" and SZ.""SpecializationId"" = {model.SpecializationId} ";
            }

            if (model.ServiceId > 0)
            {
                where += $@" and Ser.""ServiceId"" = {model.ServiceId} ";
            }

            if (model.ProviderLocationId > 0)
            {
                where +=
                    $@" and trim(Upper(PRL.""FullName"")) in (select trim(upper(""FullName"")) from  ""PracticeLocation"" where ""PracticeLocationId""={model.ProviderLocationId})";
            }

            if (model.IsTelemedicine != null)
            {
                if (Convert.ToBoolean(model.IsTelemedicine))
                {
                    where += $@" and PL.""TelemedicineDuration"" IS NOT NULL";
                }
                else
                {
                    where += $@" and PL.""ConsultationDuration"" IS NOT NULL";
                }
            }

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

            if (!string.IsNullOrEmpty(model.SearchParam))
            {
                where += $@" and (Sz.""SpecializationName"" ilike '%{model.SearchParam}%' or Ser.""ServiceName"" ilike '%{model.SearchParam}%' or P.""FullName"" ilike '%{model.SearchParam}%' or Pr.""FullName"" ilike '%{model.SearchParam}%')";
            }
            if (model.LocationId != null)
            {
                where += $@" AND PA.""LocationId"" = '{model.LocationId}' ";
            }
            if (model.ConsultationName != null)
            {
                where += $@" AND CT.""Name"" = '{model.ConsultationName}'";
            }
            var query =
                $@" SELECT distinct count(P.*) over() as ""TotalItems"" ,now()::Date, PAL.""LocationId"",PAL.""Name"" as ""Location"",Pra.""FullName"" as ""PracticeName"",
                                    PA.""SpecializationId"",P.""DepartmentId"",
                                    --PA.""StartDate"" as ""StartDate"",
                                    --PA.""EndDate"" as ""EndDate"",
                                    min (PA.""StartDate"") over (partition by PA.""ProviderId"", PA.""SpecializationId"" ,PA.""LocationId"") as ""StartDate"",
                                    max (PA.""EndDate"") over (partition by PA.""ProviderId"", PA.""SpecializationId"" ,PA.""LocationId"") as ""EndDate"",
                                    A.""AccountId"", P.""ProviderId"", P.""FullName"" as ""ProviderName"", P.""Experience"",
                                    P.""Gender"", P.""Languages"", PA.""ConsultationTypeId"",CT.""Name"" as ""ConsultationName"", --PA.""ProviderAvailabilityId"",
                                    CUN.""CurrencySymbol"",string_agg(DISTINCT Sz.""SpecializationName"", ',') as ""Specializations"",
                                    (CASE WHEN P.""ProfileImageUrl"" IS NOT NULL and P.""ProfileImageUrl"" <> '' THEN P.""ProfileImageUrl"" ELSE NULL END) AS ""ProfileImageUrl"",
                                    (CASE WHEN P.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.runningEnvironment.CurrentEnvironment}', '/', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE NULL END) AS ""ThumbnailUrl""
                                    from  ""Provider"" P
                                    join ""Account"" A on A.""ReferenceId"" = P.""ProviderId"" and A.""RoleId"" = 3 AND A.""Active"" IS TRUE
                                    left join ""ProviderAvailability"" PA on PA.""ProviderId"" = P.""ProviderId""
                                    left join ""Location"" PAL on PAL.""LocationId"" = PA.""LocationId"" And PAL.""Active"" is true
                                    left join ""ConsultationType"" CT on CT.""ConsultationTypeId"" = PA.""ConsultationTypeId""
                                    join ""Country"" CUN on CUN.""CountryId"" = P.""CountryId"" AND CUN.""Active"" IS TRUE
                                    join ""Practice"" Pra on pra.""PracticeId""=PAL.""PracticeId""
                                    left join ""Specialization"" Sz on Sz.""SpecializationId"" = PA.""SpecializationId"" AND Sz.""Active"" IS TRUE
                                    --left join ""Specialization"" Sz on Sz.""SpecializationId"" = ANY(P.""Specializations"") AND Sz.""Active"" IS TRUE
                                    left join ""Appointment"" apt on  P.""ProviderId""=apt.""ProviderId""  
                                    left join ""Patient"" pat on pat.""PatientId""=apt.""PatientId""
                                {where}
                               Group By A.""AccountId"",	PA.""SpecializationId"",P.""DepartmentId"",P.""ProviderId"",P.""FullName"",P.""Experience"",
                                P.""Gender"", P.""Languages"", CUN.""CurrencySymbol"",
                                PA.""ConsultationTypeId"",CT.""Name"",PA.""ProviderAvailabilityId""
                                ,PA.""StartDate"", PA.""EndDate""
                                ,PAL.""Name"", PAL.""LocationId"",Pra.""FullName""
                                order by
			                                 --P.""ProfileImageUrl"" ASC NULLS LAST, 
			                                --P.""ProviderId"",Sz.""SpecializationId"" 
                                P.""FullName"" asc";

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

            model.PageIndex -= 1;
            query += " LIMIT " + model.PageSize + " offset " + (model.PageIndex * model.PageSize);
            return this.unitOfWork.Current.QueryAsync<ProviderListItemModel>(query);
        }


        /// <inheritdoc />
        public Task<IEnumerable<ProviderSpecializationModel>> FetchDoctorSpecializationOpAsync(ProviderSpecializationModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += model.LocationId != null ? $@",{model.LocationId}" : ",null";
            parameters += model.ConsultationTypeId != null ? $@",{model.ConsultationTypeId}" : ",null";
            parameters += model.AppointmentDate != null ? $@",'{model.AppointmentDate}'" : ",null ";

            var query = $@"select * from ""udf_FetchDoctor_With_Availability_Specialization_Op""({parameters})";

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