namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Shared.Library.Enums;
    using Hims.Shared.UserModels.ProviderAvailability;
    using Shared.EntityModels;
    using Shared.UserModels;
    using Resource = Hims.Shared.UserModels.Discharge.Resource;
    using InsertModel = Shared.UserModels.ProviderLeave.InsertModel;
    using UpdateModel = Shared.UserModels.ProviderLeave.UpdateModel;

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

        /// <inheritdoc cref="IProviderAvailabilityService" />
        public ProviderAvailabilityServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc />
        public Task<IEnumerable<ProviderLocationModel>> FetchAsync(int providerId, bool? active, int? locationId)
        {
            var where = $@" WHERE prl.""ProviderId"" = {providerId} ";
            if (active != null)
            {
                where += $@" and prl.""Active""={(bool)active} ";
            }
            if (locationId != null)
            {
                where += $@" and prl.""LocationId"" ={locationId}";
            }

            var query = $@"SELECT prl.*, c.""CurrencySymbol"", pra.""PracticeId"", L.""Name"" AS ""PracticeLocationName"", pra.""FullName"" AS ""PracticeName"",
                                pra.""TIN"" AS ""PracticeTIN"",prl.""IsTelemedicine"",prl.""IsOnlineConsultation""
                                FROM ""ProviderLocation"" prl
                                join ""Location"" L on L.""LocationId"" = prl.""LocationId""                                
                                JOIN ""Practice"" pra ON pra.""PracticeId"" = L.""PracticeId"" AND pra.""Active"" IS TRUE
								JOIN ""Country"" c ON c.""CountryId"" = L.""CountryId""
                                 {where}
                                ORDER BY prl.""ProviderLocationId"" desc";
            return this.unitOfWork.Current.QueryAsync<ProviderLocationModel>(query);
        }

        /// <inheritdoc />
        public Task<ProviderLocationModel> FindAsync(int providerLocationId, int patientId, int? locationId)
        {
            var query = $@"Select  PL.""ProviderLocationId"", PL.""ProviderId"", PL.""LocationId"", c.""CurrencySymbol"",
                                PL.""ConsultationCharges"", PL.""TelemedicineCharges"", PL.""Duration"",
                                PL.""ConsultationDuration"",
                            PL.""TelemedicineDuration"", PL.""InPatientDuration"", PL.""OutPatientDuration"",
                        PL.""CasualtyDuration"", PL.""AvailableDays"", PL.""Availability"",

                                CASE WHEN (SELECT Count(""AppointmentId"") FROM ""Appointment"" WHERE ""ProviderId"" = PL.""ProviderId"" AND ""PatientId"" = 0 ) > 0 THEN TRUE ELSE FALSE END ""IsFallowUp""
                                
                                    from ""ProviderLocation"" PL
                                JOIN ""Location"" pral ON pral.""LocationId"" = pl.""LocationId"" AND pral.""Active"" IS TRUE
								JOIN ""Country"" c ON c.""CountryId"" = pral.""CountryId""
                                where PL.""ProviderLocationId"" = {providerLocationId} and PL.""Active"" IS True and  PL.""LocationId"" = {locationId} ";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<ProviderLocationModel>(query);
        }

        /// <inheritdoc />
        public Task<TaxModel> FetchTaxAsync()
        {
            var query = $@"Select * from ""Tax"" where ""Active"" is true";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<TaxModel>(query);
        }

        /// <inheritdoc />
        public async Task<Tuple<IEnumerable<FilterAvailabilityViewModel>, IEnumerable<FilterVisitTypeViewModel>>> FetchAvailabilitiesAsync(FilterAvailabilityViewModel model)
        {
            var where = @"WHERE 1=1 ";

            var whereVisitType = @"WHERE 1=1 ";
            var flag = @" ";
            var leaveFlag = @" ";
            var distinct = @"  ";
            var breakFlag = @"  ";
            if (model.Flag == false)
            {
                flag += $@",CONCAT(UNNEST(string_to_array(PA.""AvailableDate"", ',')), 'T', PA.""StartTime"") as ""AvailabilityStartDateTime"",
				CONCAT(UNNEST(string_to_array(PA.""AvailableDate"", ',')), 'T', PA.""EndTime"") as ""AvailabilityEndDateTime"",
                --UNNEST(string_to_array(PA.""AvailableDate"", ',')) as ""AvailableDate""
                PA.""AvailableDate"", PA.""NewPatientSlots"" ,		
				PA.""OfflineSlots"" ,PA. ""GeneralSlots"" ,PA. ""TotalSlots"" , PA.""SpecializationDuration""";

                leaveFlag += $@",CONCAT(UNNEST(string_to_array(PL.""LeaveDate""::text, ',')), 'T',PL.""ProviderLeaveStartTime""::text) as ""AvailabilityStartDateTime"",
				CONCAT(UNNEST(string_to_array(PL.""LeaveDate""::text, ',')), 'T',PL.""ProviderLeaveEndTime""::text) as ""AvailabilityEndDateTime"",
                PA.""AvailableDate"", PA.""NewPatientSlots"" ,		
				PA.""OfflineSlots"" ,PA. ""GeneralSlots"" ,PA. ""TotalSlots"" , PA.""SpecializationDuration""";

                breakFlag += $@" ,CONCAT(UNNEST(string_to_array(PRB.""BreakDate"", ',')), 'T', PRB.""StartTime"") as ""AvailabilityStartDateTime"",
                         CONCAT(UNNEST(string_to_array(PRB.""BreakDate"", ',')), 'T', PRB.""EndTime"") as ""AvailabilityEndDateTime""
                        , PRB.""BreakDate"", 0 as ""NewPatientSlots"" 		
                        , 0 as ""OfflineSlots"" ,0 as ""GeneralSlots"" ,0 as ""TotalSlots"" , 0 as ""SpecializationDuration""";
            }
            else
            {
                distinct += $@" distinct on (PA.""LocationId"") ";
            }

            if (model.ProviderId != null)
            {
                where += $@" AND PA.""ProviderId"" = {model.ProviderId}";
            }
            if (model.LocationId != null)
            {
                where += $@" AND PA.""LocationId"" = {model.LocationId}";
            }
            var query =
                 //providerLocationId == null
                 // ?
                 $@"Select {distinct} PA.""ProviderAvailabilityId"", PA.""ProviderId"",P.""FullName""  as ""ProviderName"", PA.""LocationId"", PA.""ConsultationTypeId"",CT.""Name"" as ""ConsultationTypeName""
		        , PA.""StartDate"", PA.""EndDate"", PA.""SpecializationId"", PA.""DoctorWeekId""
		        , S.""SpecializationName"", PA.""AvailableDay"", PA.""StartTime"", PA.""EndTime"",PA.""NoOfNewPatient"", PA.""NoOfOfflinePatient""
		        --, PA.""FreeFollowUpDays"", PA.""FreeFollowUpDaysLimit""
                , L.""NameLoc"" AS ""OptionalText"", L.""Name"" as ""LocationName"",

                pra.""FullName"" as ""Value"", c.""CurrencySymbol"" AS ""OptionalText2"",PA.""AvailableDate"", PA.""LeaveStartDate"", PA.""LeaveEndDate"", 'N' AS ""Leave"", PA.""IsLeave""
                ,0 as ""ProviderLeaveId"", 'null' as ""Reason"", 0 as ""ProviderBreakId"", 'null' as ""BreakType"", 'null' as ""BreakBlock""
                --,CONCAT(PA.""StartDate"", 'T', PA.""StartTime"") as ""AvailabilityStartDateTime""
                --,CONCAT(PA.""EndDate"", 'T', PA.""EndTime"") as ""AvailabilityEndDateTime""
				{flag}
                                From ""ProviderAvailability"" PA
		        left join ""Provider"" P on P.""ProviderId"" = PA.""ProviderId""
		        left join ""Location"" L on L.""LocationId"" = PA.""LocationId""
				left JOIN ""Country"" c on c.""CountryId"" = L.""CountryId""
                left JOIN ""Practice"" pra on pra.""PracticeId"" = L.""PracticeId"" AND pra.""Active"" IS TRUE
		        left join ""ConsultationType"" CT on CT.""ConsultationTypeId"" = PA.""ConsultationTypeId""
		        left join ""Specialization"" S on S.""SpecializationId"" = PA.""SpecializationId""

                         {where} and L.""Active"" = true AND L.""CountryId"" = '1' and PA.""Active"" is true

 UNION ALL Select distinct on (PL.""LeaveDate"") PL.""ProviderLeaveId"", PA.""ProviderId"",P.""FullName""  as ""ProviderName"", PL.""LocationId"", PA.""ConsultationTypeId"",CT.""Name"" as ""ConsultationTypeName""
		        , PA.""StartDate"", PA.""EndDate"", PA.""SpecializationId"",  0 as ""DoctorWeekId""
		        , S.""SpecializationName"", PA.""AvailableDay"", PL.""ProviderLeaveStartTime""::text as ""StartTime"", PL.""ProviderLeaveEndTime""::text as ""EndTime"",PA.""NoOfNewPatient"", PA.""NoOfOfflinePatient""
		       -- , PA.""FreeFollowUpDays"", PA.""FreeFollowUpDaysLimit""
                , L.""NameLoc"" AS ""OptionalText"", L.""Name"" as ""LocationName"",
				pra.""FullName"" as ""Value"", c.""CurrencySymbol"" AS ""OptionalText2"",PA.""AvailableDate"", PA.""LeaveStartDate"", PA.""LeaveEndDate"", 'L' AS ""Leave"", PA.""IsLeave""
				--,CONCAT(PA.""StartDate"", 'T', PA.""StartTime"") as ""AvailabilityStartDateTime""
                --,CONCAT(PA.""EndDate"", 'T', PA.""EndTime"") as ""AvailabilityEndDateTime""
                ,PL.""ProviderLeaveId"", PL.""Reason"", 0 as ""ProviderBreakId"", PL.""Reason"" as ""BreakType"", 'null' as ""BreakBlock""

                 { leaveFlag}
                                From ""ProviderAvailability"" PA
		        left join ""Provider"" P on P.""ProviderId"" = PA.""ProviderId""
				join ""ProviderLeave"" PL on PL.""ProviderId"" =  P.""ProviderId"" and PL.""Active"" is true
 		        left join ""Location"" L on L.""LocationId"" = PA.""LocationId""
				left JOIN ""Country"" c on c.""CountryId"" = L.""CountryId""
                left JOIN ""Practice"" pra on pra.""PracticeId"" = L.""PracticeId"" AND pra.""Active"" IS TRUE
		        left join ""ConsultationType"" CT on CT.""ConsultationTypeId"" = PA.""ConsultationTypeId""
		        left join ""Specialization"" S on S.""SpecializationId"" = PA.""SpecializationId""

                         {where} and L.""Active"" = true AND L.""CountryId"" = '1' and PA.""Active"" is true

                        UNION ALL Select distinct PRB.""ProviderBreakId"", PA.""ProviderId"",P.""FullName""  as ""ProviderName"", PRB.""LocationId"", 
                        PRB.""ConsultationTypeId"",CT.""Name"" as ""ConsultationTypeName""
                        ,PRB.""StartDate"", PRB.""EndDate"", PRB.""SpecializationId"", PRB.""DoctorWeekId""
                        , S.""SpecializationName"", PRB.""BreakDay"",  PRB.""StartTime"", PRB.""EndTime"", 0 as ""NoOfNewPatient"", 0 as  ""NoOfOfflinePatient""
                        , L.""NameLoc"" AS ""OptionalText"", L.""Name"" as ""LocationName"",
                        pra.""FullName"" as ""Value"", c.""CurrencySymbol"" AS ""OptionalText2"",PRB.""BreakDate""
                        , PA.""LeaveStartDate"", PA.""LeaveEndDate"", 'B' AS ""Leave"", PA.""IsLeave""
                        ,0 as ""ProviderLeaveId"", 'null' as ""Reason"",PRB.""ProviderBreakId"", PRB.""BreakType"", PRB.""BreakBlock""
                       
                    {breakFlag}
                                From ""ProviderAvailability"" PA
		        left join ""Provider"" P on P.""ProviderId"" = PA.""ProviderId""
				join ""ProviderBreak"" PRB on PRB.""ProviderId"" = PA.""ProviderId"" and PRB.""LocationId"" = PA.""LocationId"" and  PRB.""ConsultationTypeId"" = PA.""ConsultationTypeId"" and PRB.""SpecializationId"" = PA.""SpecializationId""
 		        left join ""Location"" L on L.""LocationId"" = PA.""LocationId""
				left JOIN ""Country"" c on c.""CountryId"" = L.""CountryId""
                left JOIN ""Practice"" pra on pra.""PracticeId"" = L.""PracticeId"" AND pra.""Active"" IS TRUE
		        left join ""ConsultationType"" CT on CT.""ConsultationTypeId"" = PA.""ConsultationTypeId""
		        left join ""Specialization"" S on S.""SpecializationId"" = PA.""SpecializationId""

                      {where} and L.""Active"" = true AND L.""CountryId"" = '1' and PA.""Active"" is true";

            var providerAvailabilityId = await this.unitOfWork.Current.QueryAsync<FilterAvailabilityViewModel>(query);

            //if (providerAvailabilityId.ToList().Count != 0)
            //{
            //    whereVisitType += $@" AND PAV.""ProviderAvailabilityId"" = { providerAvailabilityId.ToList()[0].ProviderAvailabilityId}";
            //}
            //else
            //{
            //    whereVisitType += $@" AND PAV.""ProviderAvailabilityId"" = -1";
            //}

            query = $@"select PAV.""ProviderAvailabilityVisitTypeId"",PAV.""VisitTypeId"", PAV.""Duration"", VT.""VisitorName"" 
                            from ""ProviderAvailabilityVisitType"" PAV
                            join ""VisitType"" VT on VT.""VisitTypeId"" = PAV.""VisitTypeId""

                        {whereVisitType}";

            var availabilityVisitType = await this.unitOfWork.Current.QueryAsync<FilterVisitTypeViewModel>(query);

            //return this.unitOfWork.Current.QueryAsync<FilterAvailabilityViewModel>(query);
            return new Tuple<IEnumerable<FilterAvailabilityViewModel>, IEnumerable<FilterVisitTypeViewModel>>(providerAvailabilityId, availabilityVisitType);
            //return Tuple<providerAvailabilityId,>
        }

        /// <inheritdoc />
        public Task<IEnumerable<ProviderAvailabilityDatesModel>> FetchAvailabilityDatesAsync(int providerId, int? locationId)
        {
            var query = $@"SELECT * FROM ""udf_fetchAvailableDates""({providerId},{locationId})";

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

        /// <inheritdoc />
        public Task<IEnumerable<TimeSpan>> FetchAppointmentTimesAsync(int providerLocationId, DateTime appointmentDate)
        {
            var query = $@"Select distinct ""AppointmentTime"" from ""Appointment"" where ""ProviderLocationId"" = '{providerLocationId}' AND ""AppointmentDate"" = '{appointmentDate.ToString("yyyy-MM-dd")}' AND ""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryAsync<TimeSpan>(query);
        }

        /// <inheritdoc />
        public async Task<int> AddAsync(ModifyAvailabilityModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var findExactDate = "";
            var findExactBreakDate = "";
            //var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderLocationId"") FROM ""ProviderLocation"" WHERE ""LocationId"" = '{model.LocationId}' AND  ""ProviderId"" = '{model.ProviderId}'");
            //if (checkIf > 0)
            //{
            //    return -1;
            //}
            #region accountChecking
            var findProviderAccountId = await this.unitOfWork.Accounts.FindAsync(a => a.ReferenceId == model.ProviderId && a.RoleId == (int)Roles.Provider);
            if (findProviderAccountId == null)
            {
                return -1;
            }
            //var findInAccountMap = await this.unitOfWork.LocationAccountMap.FindAsync(f => f.AccountId == findProviderAccountId.AccountId && f.LocationId == model.LocationId);
            //if (findInAccountMap == null)
            //{
            //    var accountMapModel = new LocationAccountMap
            //    {
            //        AccountId = findProviderAccountId.AccountId,
            //        LocationId = model.LocationId
            //    };
            //    accountMapModel.LocationAccountMapId = await this.unitOfWork.LocationAccountMap.InsertAsync(accountMapModel, transaction);
            //    if (accountMapModel.LocationAccountMapId == 0)
            //    {
            //        transaction.Rollback();
            //        return new int();
            //    }
            //}
            #endregion

            try
            {
                if (model.SlotTimings.Count == 0)
                {
                    return -1;
                }
                foreach (var slot in model.SlotTimings)
                {
                    if (slot.SlotTimingsLocationWise.Count > 0)
                    {
                        try
                        {
                            foreach (var locationSlot in slot.SlotTimingsLocationWise)
                            {
                                var findInAccountMap = await this.unitOfWork.LocationAccountMap.FindAsync(f => f.AccountId == findProviderAccountId.AccountId && f.LocationId == slot.LocationId);
                                if (findInAccountMap == null)
                                {
                                    var accountMapModel = new LocationAccountMap
                                    {
                                        AccountId = findProviderAccountId.AccountId,
                                        LocationId = slot.LocationId
                                    };
                                    accountMapModel.LocationAccountMapId = await this.unitOfWork.LocationAccountMap.InsertAsync(accountMapModel, transaction);
                                    if (accountMapModel.LocationAccountMapId == 0)
                                    {
                                        transaction.Rollback();
                                        return new int();
                                    }
                                }
                                if (locationSlot.ProviderAvailabilityId > 0)
                                {
                                    var providerAvailabilityId = await this.unitOfWork.ProviderAvailability.FindAsync(m => m.ProviderAvailabilityId == locationSlot.ProviderAvailabilityId && m.ConsultationTypeId == locationSlot.ConsultationTypeId && m.SpecializationId == locationSlot.SpecializationIds && m.LocationId == slot.LocationId && m.Active == true);

                                    if (model.Availability != null)
                                    {
                                        var diffDates = model.Availability.Split(",").ToList();
                                        foreach (var singleDate in diffDates)
                                        {
                                            var query = $@" select * from ""ProviderAvailability""
                                                where ""ProviderId"" = {model.ProviderId} 
                                                and ""AvailableDate"" ilike '%{singleDate}%'
                                                --and ""StartDate""::Date <= '{model.FromDate}' and ""EndDate"" >= '{model.ToDate}' 
                                                and ""StartTime""::time without time zone <= '{locationSlot.FromTime}'::time without time zone
                                                and ""EndTime""::time without time zone >= '{locationSlot.ToTime}'::time without time zone and ""Active"" is true";
                                            var providerAvailabilityIds = await this.unitOfWork.Current.QueryAsync<FilterAvailabilityViewModel>(query);
                                            providerAvailabilityIds.ToList();
                                            //var providerAvailabilityIds = await this.unitOfWork.ProviderAvailability.FindAllAsync(m => m.ProviderId == model.ProviderId && DateTime.Parse(m.StartDate) <= DateTime.Parse(model.FromDate) && DateTime.Parse(m.EndDate) >= DateTime.Parse(model.ToDate) && TimeSpan.Parse( m.StartTime) <= TimeSpan.Parse(slot.FromTime) && TimeSpan.Parse(m.EndTime) >= TimeSpan.Parse(slot.ToTime));
                                            if (providerAvailabilityIds.Count() > 0)
                                            {
                                                var checkavailabilityExists = providerAvailabilityIds.Where(m => m.ProviderAvailabilityId == locationSlot.ProviderAvailabilityId).ToList();
                                                if (checkavailabilityExists.Count() == 0)
                                                {
                                                    return -1;
                                                }
                                            }
                                        }

                                    }

                                    if (providerAvailabilityId != null)
                                    {
                                        if (providerAvailabilityId.AvailableDate != null)
                                        {
                                            var datesArray = providerAvailabilityId.AvailableDate.Split(",").ToList();
                                            findExactDate = datesArray.Find(x => x == model.FromDate);
                                        }
                                        if (findExactDate == model.FromDate)
                                        {
                                            providerAvailabilityId.ModifiedBy = model.CreatedBy;
                                            providerAvailabilityId.ModifiedDate = DateTime.Now;
                                            providerAvailabilityId.LocationId = slot.LocationId;
                                            providerAvailabilityId.ConsultationTypeId = locationSlot.ConsultationTypeId;
                                            providerAvailabilityId.StartDate = model.FromDate;
                                            providerAvailabilityId.EndDate = model.ToDate;
                                            providerAvailabilityId.StartTime = locationSlot.FromTime;
                                            providerAvailabilityId.EndTime = locationSlot.ToTime;
                                            providerAvailabilityId.AvailableDay = model.AvailableDays;
                                            providerAvailabilityId.SpecializationId = locationSlot.SpecializationIds;
                                            providerAvailabilityId.AvailableDate = model.Availability;
                                            providerAvailabilityId.LeaveStartDate = model.LeaveFromDate;
                                            providerAvailabilityId.LeaveEndDate = model.LeaveToDate;
                                            providerAvailabilityId.IsLeave = model.IsLeave;
                                            providerAvailabilityId.NoOfNewPatient = locationSlot.NoOfNewPatient;
                                            providerAvailabilityId.NoOfOfflinePatient = locationSlot.NoOfOfflinePatient;
                                            providerAvailabilityId.NewPatientSlots = locationSlot.NoOfNewPatientSlots;
                                            providerAvailabilityId.OfflineSlots = locationSlot.NoOfOfflinePatientSlots;
                                            providerAvailabilityId.GeneralSlots = locationSlot.GeneralSlots;
                                            providerAvailabilityId.TotalSlots = locationSlot.TotalSlots;
                                            providerAvailabilityId.SpecializationDuration = locationSlot.SpecializationDuration;
                                            providerAvailabilityId.DoctorWeekId = model.DoctorWeekId;

                                            var providerAvailability = await this.unitOfWork.ProviderAvailability.UpdateAsync(providerAvailabilityId, transaction);
                                            if (providerAvailability == 0)
                                            {
                                                transaction.Rollback();
                                                return new int();
                                            }
                                        }

                                        else if (providerAvailabilityId != null)
                                        {

                                            providerAvailabilityId.ModifiedBy = model.CreatedBy;
                                            providerAvailabilityId.ModifiedDate = DateTime.Now;
                                            providerAvailabilityId.LocationId = slot.LocationId;
                                            providerAvailabilityId.ConsultationTypeId = locationSlot.ConsultationTypeId;
                                            providerAvailabilityId.StartDate = model.FromDate;
                                            providerAvailabilityId.EndDate = model.ToDate;
                                            providerAvailabilityId.StartTime = locationSlot.FromTime;
                                            providerAvailabilityId.EndTime = locationSlot.ToTime;
                                            providerAvailabilityId.AvailableDay = model.AvailableDays;
                                            providerAvailabilityId.SpecializationId = locationSlot.SpecializationIds;
                                            providerAvailabilityId.AvailableDate = model.Availability;
                                            providerAvailabilityId.LeaveStartDate = model.LeaveFromDate;
                                            providerAvailabilityId.LeaveEndDate = model.LeaveToDate;
                                            providerAvailabilityId.IsLeave = model.IsLeave;
                                            providerAvailabilityId.NoOfNewPatient = locationSlot.NoOfNewPatient;
                                            providerAvailabilityId.NoOfOfflinePatient = locationSlot.NoOfOfflinePatient;
                                            providerAvailabilityId.NewPatientSlots = locationSlot.NoOfNewPatientSlots;
                                            providerAvailabilityId.OfflineSlots = locationSlot.NoOfOfflinePatientSlots;
                                            providerAvailabilityId.GeneralSlots = locationSlot.GeneralSlots;
                                            providerAvailabilityId.TotalSlots = locationSlot.TotalSlots;
                                            providerAvailabilityId.SpecializationDuration = locationSlot.SpecializationDuration;
                                            providerAvailabilityId.DoctorWeekId = model.DoctorWeekId;

                                            var providerAvailabilityWeeklyBiweekly = await this.unitOfWork.ProviderAvailability.UpdateAsync(providerAvailabilityId, transaction);
                                            if (providerAvailabilityWeeklyBiweekly == 0)
                                            {
                                                transaction.Rollback();
                                                return new int();
                                            }
                                        }

                                        else if (providerAvailabilityId.StartDate == model.FromDate && providerAvailabilityId.EndDate == model.ToDate && providerAvailabilityId.StartTime == locationSlot.FromTime && providerAvailabilityId.EndTime == locationSlot.ToTime)
                                        {
                                            return -1;
                                        }
                                    }
                                    else if (providerAvailabilityId == null)
                                    {
                                        var providerAvailabilityInsert = new ProviderAvailability
                                        {
                                            Active = true,
                                            ProviderId = model.ProviderId,
                                            LocationId = slot.LocationId,
                                            ConsultationTypeId = locationSlot.ConsultationTypeId,
                                            CreatedBy = model.CreatedBy,
                                            CreatedDate = DateTime.UtcNow,
                                            StartDate = model.FromDate,
                                            EndDate = model.ToDate,
                                            SpecializationId = locationSlot.SpecializationIds,
                                            AvailableDate = model.Availability,
                                            AvailableDay = model.AvailableDays,
                                            StartTime = locationSlot.FromTime,
                                            EndTime = locationSlot.ToTime,
                                            LeaveStartDate = model.LeaveFromDate,
                                            LeaveEndDate = model.LeaveToDate,
                                            IsLeave = model.IsLeave,
                                            NoOfNewPatient = locationSlot.NoOfNewPatient,
                                            NoOfOfflinePatient = locationSlot.NoOfOfflinePatient,
                                            NewPatientSlots = locationSlot.NoOfNewPatientSlots,
                                            OfflineSlots = locationSlot.NoOfOfflinePatientSlots,
                                            GeneralSlots = locationSlot.GeneralSlots,
                                            TotalSlots = locationSlot.TotalSlots,
                                            SpecializationDuration = locationSlot.SpecializationDuration,
                                            DoctorWeekId = model.DoctorWeekId

                                        };

                                        providerAvailabilityInsert.ProviderAvailabilityId = await this.unitOfWork.ProviderAvailability.InsertAsync(providerAvailabilityInsert, transaction);

                                        if (providerAvailabilityInsert.ProviderAvailabilityId == 0)
                                        {
                                            transaction.Rollback();
                                            return new int();
                                        }
                                    }
                                }
                                else
                                {
                                    if (model.Availability != null)
                                    {
                                        var diffNewDates = model.Availability.Split(",").ToList();
                                        foreach (var singleNewDate in diffNewDates)
                                        {
                                            var quer = $@" select * from ""ProviderAvailability""
                                                where ""ProviderId"" = {model.ProviderId}
                                                 and ""AvailableDate"" ilike '%{singleNewDate}%'
                                                --and ""StartDate""::Date <= '{model.FromDate}' and ""EndDate"" >= '{model.ToDate}' 
                                                and ""StartTime""::time without time zone <= '{locationSlot.FromTime}'::time without time zone
                                                and ""EndTime""::time without time zone >= '{locationSlot.ToTime}'::time without time zone and ""Active"" is true";
                                            var newProviderAvailabilityIds = await this.unitOfWork.Current.QueryAsync<FilterAvailabilityViewModel>(quer);
                                            newProviderAvailabilityIds.ToList();
                                            //var providerAvailabilityIds = await this.unitOfWork.ProviderAvailability.FindAllAsync(m => m.ProviderId == model.ProviderId && DateTime.Parse(m.StartDate) <= DateTime.Parse(model.FromDate) && DateTime.Parse(m.EndDate) >= DateTime.Parse(model.ToDate) && TimeSpan.Parse( m.StartTime) <= TimeSpan.Parse(slot.FromTime) && TimeSpan.Parse(m.EndTime) >= TimeSpan.Parse(slot.ToTime));
                                            if (newProviderAvailabilityIds.Count() > 0)
                                            {
                                                return -1;
                                            }
                                        }
                                    }

                                    var providerAvailabilityInsert = new ProviderAvailability
                                    {
                                        Active = true,
                                        ProviderId = model.ProviderId,
                                        LocationId = slot.LocationId,
                                        ConsultationTypeId = locationSlot.ConsultationTypeId,
                                        CreatedBy = model.CreatedBy,
                                        CreatedDate = DateTime.UtcNow,
                                        StartDate = model.FromDate,
                                        EndDate = model.ToDate,
                                        SpecializationId = locationSlot.SpecializationIds,
                                        AvailableDate = model.Availability,
                                        AvailableDay = model.AvailableDays,
                                        StartTime = locationSlot.FromTime,
                                        EndTime = locationSlot.ToTime,
                                        LeaveStartDate = model.LeaveFromDate,
                                        LeaveEndDate = model.LeaveToDate,
                                        IsLeave = model.IsLeave,
                                        NoOfNewPatient = locationSlot.NoOfNewPatient,
                                        NoOfOfflinePatient = locationSlot.NoOfOfflinePatient,
                                        NewPatientSlots = locationSlot.NoOfNewPatientSlots,
                                        OfflineSlots = locationSlot.NoOfOfflinePatientSlots,
                                        GeneralSlots = locationSlot.GeneralSlots,
                                        TotalSlots = locationSlot.TotalSlots,
                                        SpecializationDuration = locationSlot.SpecializationDuration,
                                        DoctorWeekId = model.DoctorWeekId
                                    };
                                    providerAvailabilityInsert.ProviderAvailabilityId = await this.unitOfWork.ProviderAvailability.InsertAsync(providerAvailabilityInsert, transaction);
                                    if (providerAvailabilityInsert.ProviderAvailabilityId == 0)
                                    {
                                        transaction.Rollback();
                                        return new int();
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            ex.Message.ToString();
                            transaction.Rollback();
                        }
                    }
                    try
                    {
                        if (slot.SlotBreaksLocationWise.Count > 0)
                        {
                            foreach (var breakSlot in slot.SlotBreaksLocationWise)
                            {
                                if (breakSlot.ProviderBreakId > 0)
                                {
                                    var ProviderBreakId = await this.unitOfWork.ProviderBreak.FindAsync(m => m.ProviderBreakId == breakSlot.ProviderBreakId);

                                    if (model.Availability != null)
                                    {
                                        var diffBreakDates = model.Availability.Split(",").ToList();
                                        foreach (var singleBreakDate in diffBreakDates)
                                        {

                                            var query = $@" select * from ""ProviderBreak""
                                                where ""ProviderId"" = {model.ProviderId} 
                                                --and ""StartDate""::Date <= '{model.FromDate}' and ""EndDate"" >= '{model.ToDate}' 
                                                and ""BreakDate"" ilike '%{singleBreakDate}%'
                                                and  ""StartTime""::time without time zone <= '{breakSlot.BreakFromTime}'::time without time zone
                                                and ""EndTime""::time without time zone >= '{breakSlot.BreakToTime}'::time without time zone";
                                            var providerBreakIds = await this.unitOfWork.Current.QueryAsync<BreakTimingsLocationWise>(query);
                                            providerBreakIds.ToList();
                                            //var providerAvailabilityIds = await this.unitOfWork.ProviderAvailability.FindAllAsync(m => m.ProviderId == model.ProviderId && DateTime.Parse(m.StartDate) <= DateTime.Parse(model.FromDate) && DateTime.Parse(m.EndDate) >= DateTime.Parse(model.ToDate) && TimeSpan.Parse( m.StartTime) <= TimeSpan.Parse(slot.FromTime) && TimeSpan.Parse(m.EndTime) >= TimeSpan.Parse(slot.ToTime));
                                            if (providerBreakIds.Count() > 0)
                                            {
                                                var checkavailabilityExists = providerBreakIds.Where(m => m.ProviderBreakId == breakSlot.ProviderBreakId).ToList();
                                                if (checkavailabilityExists.Count() == 0)
                                                {
                                                    return -1;
                                                }
                                            }
                                        }

                                    }

                                    if (ProviderBreakId.BreakDate != null)
                                    {
                                        var datesArray = ProviderBreakId.BreakDate.Split(",").ToList();
                                        findExactBreakDate = datesArray.Find(x => x == model.FromDate);
                                    }
                                    if (findExactBreakDate == model.FromDate)
                                    {
                                        ProviderBreakId.ModifiedBy = model.CreatedBy;
                                        ProviderBreakId.ModifiedDate = DateTime.Now;
                                        ProviderBreakId.LocationId = slot.LocationId;
                                        ProviderBreakId.ConsultationTypeId = breakSlot.BreakConsultationTypeId;
                                        ProviderBreakId.StartDate = model.FromDate;
                                        ProviderBreakId.EndDate = model.ToDate;
                                        ProviderBreakId.StartTime = breakSlot.BreakFromTime;
                                        ProviderBreakId.EndTime = breakSlot.BreakToTime;
                                        ProviderBreakId.BreakDate = model.Availability;
                                        ProviderBreakId.BreakDay = model.AvailableDays;
                                        ProviderBreakId.SpecializationId = breakSlot.BreakSpecializationId;
                                        ProviderBreakId.BreakType = breakSlot.BreakType;
                                        ProviderBreakId.BreakBlock = breakSlot.BreakBlock;

                                        ProviderBreakId.DoctorWeekId = model.DoctorWeekId;
                                        var providerBreak = await this.unitOfWork.ProviderBreak.UpdateAsync(ProviderBreakId, transaction);
                                        if (providerBreak == 0)
                                        {
                                            transaction.Rollback();
                                            return new int();
                                        }
                                    }

                                    else if (ProviderBreakId != null)
                                    {

                                        ProviderBreakId.ModifiedBy = model.CreatedBy;
                                        ProviderBreakId.ModifiedDate = DateTime.Now;
                                        ProviderBreakId.LocationId = slot.LocationId;
                                        ProviderBreakId.ConsultationTypeId = breakSlot.BreakConsultationTypeId;
                                        ProviderBreakId.StartDate = model.FromDate;
                                        ProviderBreakId.EndDate = model.ToDate;
                                        ProviderBreakId.StartTime = breakSlot.BreakFromTime;
                                        ProviderBreakId.EndTime = breakSlot.BreakToTime;
                                        ProviderBreakId.BreakDate = model.Availability;
                                        ProviderBreakId.BreakDay = model.AvailableDays;
                                        ProviderBreakId.SpecializationId = breakSlot.BreakSpecializationId;
                                        ProviderBreakId.BreakType = breakSlot.BreakType;
                                        ProviderBreakId.BreakBlock = breakSlot.BreakBlock;

                                        ProviderBreakId.DoctorWeekId = model.DoctorWeekId;
                                        var providerBreakNew = await this.unitOfWork.ProviderBreak.UpdateAsync(ProviderBreakId, transaction);
                                        if (providerBreakNew == 0)
                                        {
                                            transaction.Rollback();
                                            return new int();
                                        }

                                    }

                                    else if (ProviderBreakId.StartDate == model.FromDate && ProviderBreakId.EndDate == model.ToDate && ProviderBreakId.StartTime == breakSlot.BreakFromTime && ProviderBreakId.EndTime == breakSlot.BreakToTime)
                                    {
                                        return -1;
                                    }

                                    else if (ProviderBreakId == null)
                                    {
                                        var providerBreakInsert = new ProviderBreak
                                        {

                                            Active = true,
                                            ProviderId = model.ProviderId,
                                            LocationId = slot.LocationId,
                                            ConsultationTypeId = breakSlot.BreakConsultationTypeId,
                                            CreatedBy = model.CreatedBy,
                                            CreatedDate = DateTime.UtcNow,
                                            StartDate = model.FromDate,
                                            EndDate = model.ToDate,
                                            SpecializationId = breakSlot.BreakSpecializationId,
                                            BreakDate = model.Availability,
                                            BreakDay = model.AvailableDays,
                                            StartTime = breakSlot.BreakFromTime,
                                            EndTime = breakSlot.BreakToTime,
                                            BreakType = breakSlot.BreakType,
                                            BreakBlock = breakSlot.BreakBlock,
                                            DoctorWeekId = model.DoctorWeekId
                                        };
                                        providerBreakInsert.ProviderBreakId = await this.unitOfWork.ProviderBreak.InsertAsync(providerBreakInsert, transaction);

                                        if (providerBreakInsert.ProviderBreakId == 0)
                                        {
                                            transaction.Rollback();
                                            return new int();
                                        }
                                    }
                                }
                                else
                                {

                                    if (model.Availability != null)
                                    {
                                        var diffNewBreakDates = model.Availability.Split(",").ToList();
                                        foreach (var singleNewBreakDate in diffNewBreakDates)
                                        {

                                            var quer = $@" select * from ""ProviderBreak""
                                                where ""ProviderId"" = {model.ProviderId} 
                                                --and ""StartDate""::Date <= '{model.FromDate}' and ""EndDate"" >= '{model.ToDate}' 
                                                 and ""BreakDate"" ilike '%{singleNewBreakDate}%'
                                                and ""StartTime""::time without time zone <= '{breakSlot.BreakFromTime}'::time without time zone
                                                and ""EndTime""::time without time zone >= '{breakSlot.BreakToTime}'::time without time zone";
                                            var newProviderBreakIds = await this.unitOfWork.Current.QueryAsync<FilterAvailabilityViewModel>(quer);
                                            newProviderBreakIds.ToList();
                                            //var providerAvailabilityIds = await this.unitOfWork.ProviderAvailability.FindAllAsync(m => m.ProviderId == model.ProviderId && DateTime.Parse(m.StartDate) <= DateTime.Parse(model.FromDate) && DateTime.Parse(m.EndDate) >= DateTime.Parse(model.ToDate) && TimeSpan.Parse( m.StartTime) <= TimeSpan.Parse(slot.FromTime) && TimeSpan.Parse(m.EndTime) >= TimeSpan.Parse(slot.ToTime));
                                            if (newProviderBreakIds.Count() > 0)
                                            {
                                                return -1;
                                            }
                                        }
                                    }

                                    var providerBreakInsert = new ProviderBreak
                                    {
                                        Active = true,
                                        ProviderId = model.ProviderId,
                                        LocationId = slot.LocationId,
                                        ConsultationTypeId = breakSlot.BreakConsultationTypeId,
                                        CreatedBy = model.CreatedBy,
                                        CreatedDate = DateTime.UtcNow,
                                        StartDate = model.FromDate,
                                        EndDate = model.ToDate,
                                        SpecializationId = breakSlot.BreakSpecializationId,
                                        BreakDate = model.Availability,
                                        BreakDay = model.AvailableDays,
                                        StartTime = breakSlot.BreakFromTime,
                                        EndTime = breakSlot.BreakToTime,
                                        BreakType = breakSlot.BreakType,
                                        BreakBlock = breakSlot.BreakBlock,
                                        DoctorWeekId = model.DoctorWeekId
                                    };
                                    providerBreakInsert.ProviderBreakId = await this.unitOfWork.ProviderBreak.InsertAsync(providerBreakInsert, transaction);
                                    if (providerBreakInsert.ProviderBreakId == 0)
                                    {
                                        transaction.Rollback();
                                        return new int();
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.Message.ToString();
                        transaction.Rollback();
                    }
                }
            }
            catch (Exception e)
            {
                e.Message.ToString();
                transaction.Rollback();
            }
            transaction.Commit();
            return 2;
        }

        /// <inheritdoc />
        //public async Task<int> UpdateAsync(ModifyAvailabilityModel model)
        //{
        //    var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""ProviderLocationId"") FROM ""ProviderLocation"" WHERE ""LocationId"" = '{model.LocationId}' AND  ""ProviderId"" = '{model.ProviderId}' AND ""ProviderLocationId"" <> {model.ProviderLocationId}");
        //    if (checkIf > 0)
        //    {
        //        return -1;
        //    }

        //    var providerAvailability = await this.unitOfWork.ProviderAvailability.FindAsync(m => m.ProviderAvailabilityId == model.ProviderAvailabilityId);
        //    //providerLocation.ProviderId = model.ProviderId;
        //    //providerLocation.LocationId = model.LocationId;
        //    //providerLocation.ConsultationDuration = model.ConsultationDuration;
        //    //providerLocation.ConsultationCharges = model.ConsultationCharges;
        //    //providerLocation.TelemedicineDuration = model.TelemedicineDuration;
        //    //providerLocation.TelemedicineCharges = model.TelemedicineCharges;
        //    //providerLocation.InPatientDuration = model.InPatientDuration;
        //    //providerLocation.OutPatientDuration = model.OutPatientDuration;
        //    //providerLocation.CasualtyDuration = model.CasualtyDuration;
        //    //providerLocation.FollowUpDays = model.FollowUpDays;
        //    //providerLocation.AvailableDays = model.AvailableDays;
        //    //providerLocation.Availability = model.Availability;
        //    //providerLocation.ModifiedBy = model.ModifiedBy;
        //    //providerLocation.ModifiedDate = DateTime.UtcNow;
        //    //providerLocation.FollowUpDaysForIp = model.FollowUpDaysForIp;
        //    //providerLocation.Duration = model.Duration;
        //    //providerLocation.IsTelemedicine = model.IsTelemedicine;
        //    //providerLocation.IsOnlineConsultation = model.IsOnlineConsultation;
        //    return await this.unitOfWork.ProviderLocations.UpdateAsync(providerAvailability);
        //}

        /// <inheritdoc />
        public Task<int> DeleteAsync(int providerLocationId)
        {
            var query = $@"DELETE FROM ""ProviderLocation"" WHERE ""ProviderLocationId""= {providerLocationId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public Task<int> ModifyStatusAsync(int providerLocationId, int modifiedBy, bool status)
        {
            var query = $@"UPDATE ""ProviderLocation"" SET ""Active"" = {status}, ""ModifiedBy"" = {modifiedBy}, ""ModifiedDate"" = NOW() AT TIME ZONE 'UTC' WHERE ""ProviderLocationId""= {providerLocationId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc />
        public async Task<string> FindProviderByProviderLocationId(int providerLocationId)
        {
            //var query = $@"SELECT ""FullName"" FROM ""ProviderLocation"" pl WHERE PL.""ProviderId"" = (SELECT ""ProviderId"" FROM ""ProviderLocation"" pl WHERE .""ProviderLocationId"" = {providerLocationId})";
            var query = $@"SELECT p.""FullName"" as ""ProviderName"" FROM ""ProviderLocation"" PL join ""Provider"" p on p.""ProviderId""=PL.""ProviderId"" WHERE ""ProviderLocationId"" ={providerLocationId} ";

            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<Resource.ViewModel>> FetchVisitTypesAsync()
        {
            var query = $@"SELECT
	                        ""VisitTypeId"" AS ""Id"",
	                        ""VisitorName"" AS ""Name"" 
                        FROM
	                        ""VisitType"" where ""VisitTypeFor"" = 'OP'";
            var records = await this.unitOfWork.Current.QueryAsync<Resource.ViewModel>(query);
            return records;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<Resource.ViewModel>> FetchVisitTypeIpAsync()
        {
            var query = $@"SELECT
	                        ""VisitTypeId"" AS ""Id"",
	                        ""VisitorName"" AS ""Name"" 
                        FROM
	                        ""VisitType"" where ""VisitTypeFor"" = 'IP'";
            var records = await this.unitOfWork.Current.QueryAsync<Resource.ViewModel>(query);
            return records;
        }

        /// <inheritdoc />
        public async Task<IEnumerable<Resource.ViewModel>> FetchChargeTypesAsync()
        {
            var query = $@"SELECT
	                        ""ChargeTypesId"" AS ""Id"",
	                        ""ChargeName"" AS ""Name"" 
                        FROM
	                        ""ChargeTypes"" ";
            var records = await this.unitOfWork.Current.QueryAsync<Resource.ViewModel>(query);
            return records;
        }

        /// <inheritdoc />
        public async Task<int> AddOperationAvailabilityAsync(ProviderLocationModel model)
        {
            var availability = new ProviderLocationOperation
            {
                Availability = model.Availability,
                AvailableDays = model.AvailableDays,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                Duration = int.Parse(model.Duration),
                PracticeLocationId = model.LocationId,
                ProviderId = model.ProviderId
            };

            return await this.unitOfWork.ProviderLocationOperations.InsertAsync(availability);
        }

        /// <inheritdoc />
        public Task<IEnumerable<ProviderLocationModel>> FetchProviderOperationAvailabiltyAsync(int providerId, bool? active)
        {
            var where = $@" WHERE prlo.""ProviderId"" = {providerId} ";
            if (active != null)
            {
                where += $@" and prlo.""Active""={(bool)active} ";
            }

            var query = $@"SELECT prlo.*, c.""CurrencySymbol"", pra.""PracticeId"", pral.""FullName"" AS ""PracticeLocationName"", 
                                pra.""FullName"" AS ""PracticeName"", pra.""TIN"" AS ""PracticeTIN""
                                FROM ""ProviderLocationOperation"" prlo
                                JOIN ""PracticeLocation"" pral ON pral.""PracticeLocationId"" = prlo.""PracticeLocationId"" AND pral.""Active"" IS TRUE
                                JOIN ""Practice"" pra ON pra.""PracticeId"" = pral.""PracticeId"" AND pra.""Active"" IS TRUE
								JOIN ""Country"" c ON c.""CountryId"" = pral.""CountryId""
                                 {where}
                                ORDER BY prlo.""ProviderLocationOperationId"" DESC";
            return this.unitOfWork.Current.QueryAsync<ProviderLocationModel>(query);
        }

        public async Task<int> UpdateOperationAvailabilityAsync(ProviderLocationModel model)
        {
            var availability = await this.unitOfWork.ProviderLocationOperations.FindAsync(m => m.ProviderLocationOperationId == model.ProviderLocationOperationId);
            if (availability == null)
            {
                return -1;
            }

            availability.ModifiedBy = model.CreatedBy;
            availability.ModifiedDate = DateTime.Now;
            availability.Availability = model.Availability;
            availability.AvailableDays = model.AvailableDays;
            availability.Duration = int.Parse(model.Duration);
            availability.PracticeLocationId = model.LocationId;

            return await this.unitOfWork.ProviderLocationOperations.UpdateAsync(availability);
        }

        public async Task<int> UpdateAsync(ModifyAvailabilityModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var providerAvailabilityId = await this.unitOfWork.ProviderAvailability.FindAsync(m => m.ProviderAvailabilityId == model.ProviderAvailabilityId && m.Active == true);
            if (providerAvailabilityId == null)
            {
                return -1;
            }
            try
            {

                providerAvailabilityId.ModifiedBy = model.CreatedBy;
                providerAvailabilityId.ModifiedDate = DateTime.Now;
                providerAvailabilityId.LocationId = model.LocationId;
                providerAvailabilityId.ConsultationTypeId = model.ConsultationTypeId;
                providerAvailabilityId.StartDate = model.FromDate;
                providerAvailabilityId.EndDate = model.ToDate;

                providerAvailabilityId.ProviderAvailabilityId = await this.unitOfWork.ProviderAvailability.UpdateAsync(providerAvailabilityId, transaction);

                if (providerAvailabilityId.ProviderAvailabilityId == 0)
                {
                    transaction.Rollback();
                    return new int();
                }
                //else
                //{
                //    model.ProviderAvailabilityId = providerAvailabilityId.ProviderAvailabilityId;
                //}
            }
            catch (Exception e)
            {
                transaction.Rollback();
                e.Message.ToString();
            }
            try
            {
                //var ProviderAvailabilitySlot = await this.unitOfWork.ProviderAvailabilitySlot.FindAsync(m => m.ProviderAvailabilityId == model.ProviderAvailabilityId);
                var query = $@"DELETE FROM ""ProviderAvailabilitySlot"" WHERE ""ProviderAvailabilityId""= {model.ProviderAvailabilityId}";
                var deltedAvailabilitySlot = await this.unitOfWork.Current.ExecuteAsync(query);

                //Provider Availability slots
                foreach (var slot in model.SlotTimings)
                {
                    //foreach (var specialization in slot.SpecializationIds)//.Select(s => new ProviderAvailabilitySlot
                    // {
                    var providerAvailabilitySlot = new ProviderAvailabilitySlot
                    {
                        ProviderAvailabilityId = model.ProviderAvailabilityId,
                        StartTime = slot.FromTime,
                        EndTime = slot.ToTime,
                        SpecializationId = slot.SpecializationIds,
                        AvailableDay = model.AvailableDays,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.UtcNow,
                        Active = true,
                        //FreeFollowUpDays = slot.FollowUpDays,
                        //FreeFollowUpDaysLimit = slot.FollowUpDaysLimit,
                    };
                    var providerAvailabilitySlotInsertId = await this.unitOfWork.ProviderAvailabilitySlot.InsertAsync(providerAvailabilitySlot, transaction);
                    if (providerAvailabilitySlotInsertId == 0)
                    {
                        transaction.Rollback();
                        return new int();
                    }
                    //};
                }

            }
            catch (Exception e)
            {
                transaction.Rollback();
                e.Message.ToString();
            }

            try
            {
                var query = $@"DELETE FROM ""ProviderAvailabilityVisitType"" WHERE ""ProviderAvailabilityId""= {model.ProviderAvailabilityId}";
                var deltedAvailabilitySlot = await this.unitOfWork.Current.ExecuteAsync(query);
                //Provider Availability visit
                foreach (var slot in model.Duration)
                {
                    var providerAvailabilityVisitType = new ProviderAvailabilityVisitType
                    {
                        VisitTypeId = slot.Id,
                        Duration = slot.Value,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.UtcNow,
                        Active = true
                    };
                    var providerAvailabilityVisitTypeInsertId = await this.unitOfWork.ProviderAvailabilityVisitType.InsertAsync(providerAvailabilityVisitType, transaction);
                    if (providerAvailabilityVisitTypeInsertId == 0)
                    {
                        transaction.Rollback();
                        return new int();
                    }
                }

            }
            catch (Exception e)
            {
                transaction.Rollback();
                e.Message.ToString();
            }
            transaction.Commit();
            return (int)model.ProviderAvailabilityId;
        }

        /// <summary>
        /// the add provider leave async.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<int> AddProviderLeaveAsync(InsertModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var leaveDates = model.LeaveDates.Split(",").ToList();
            //var providerLeaveCheck = await this.unitOfWork.ProviderLeaves.FindAsync(m => m.LeaveDate == leaves.Contains(Convert.ToDateTime(m.LeaveDate)));
            //if (providerLeaveCheck == null)
            //{
            //    return -1;
            //}
            foreach (var leaveDate in leaveDates)
            {
                try
                {
                    //var query = $@"select * from ""ProviderLeave"" where ""LeaveDate""::Date = '{leaveDate}'::Date and ""ProviderId"" = {model.ProviderId} and ""Active"" is true";
                    //var providerLeaveCheck = await this.unitOfWork.Current.QueryAsync<ProviderAvailability>(query);
                    var providerLeaveCheck = await this.unitOfWork.ProviderLeaves.FindAsync(m => m.LeaveDate == Convert.ToDateTime(leaveDate) && m.ProviderId == model.ProviderId && m.Active == true);
                    if (providerLeaveCheck != null)
                    {
                        providerLeaveCheck.Active = true;
                        providerLeaveCheck.LeaveDate = Convert.ToDateTime(leaveDate);
                        providerLeaveCheck.Reason = model.Reason;
                        providerLeaveCheck.ModifiedBy = model.CreatedBy;
                        providerLeaveCheck.ModifiedDate = DateTime.Now;
                        providerLeaveCheck.LocationId = model.LeaveLocationId;
                        providerLeaveCheck.ProviderLeaveStartTime = TimeSpan.Parse(model.ProviderLeaveStartTime);
                        providerLeaveCheck.ProviderLeaveEndTime = TimeSpan.Parse(model.ProviderLeaveEndTime);
                        var updatedLeave = await this.unitOfWork.ProviderLeaves.UpdateAsync(providerLeaveCheck, transaction);
                        if (updatedLeave == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }
                    }
                    else
                    {
                        var providerLeave = new ProviderLeave
                        {
                            Active = true,
                            LeaveDate = Convert.ToDateTime(leaveDate),
                            Reason = model.Reason,
                            ProviderId = model.ProviderId,
                            CreatedBy = model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            LocationId = model.LeaveLocationId,
                            ProviderLeaveStartTime = TimeSpan.Parse(model.ProviderLeaveStartTime),
                            ProviderLeaveEndTime = TimeSpan.Parse(model.ProviderLeaveEndTime)

                        };
                        var providerLeaveInserted = await this.unitOfWork.ProviderLeaves.InsertAsync(providerLeave, transaction);
                        if (providerLeaveInserted == 0)
                        {
                            transaction.Rollback();
                            return 0;
                        }

                    }

                }
                catch (Exception ex)
                {
                    ex.Message.ToString();
                    transaction.Rollback();
                    return 0;
                }
            }
            transaction.Commit();
            return 1;

        }


        /// <summary>
        /// the add provider leave async.
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task<int> UpdateProviderLeaveAsync(UpdateModel model)
        {
            try
            {

                var providerLeave = await this.unitOfWork.ProviderLeaves.FindAsync(m => m.ProviderLeaveId == (model.ProviderLeaveId));
                providerLeave.Active = true;
                providerLeave.LeaveDate = Convert.ToDateTime(model.LeaveDates);
                providerLeave.Reason = model.Reason;
                providerLeave.ModifiedBy = model.ModifiedBy;
                providerLeave.ModifiedDate = DateTime.Now;
                providerLeave.LocationId = model.LeaveLocationId;
                providerLeave.ProviderLeaveStartTime = TimeSpan.Parse(model.ProviderLeaveStartTime);
                providerLeave.ProviderLeaveEndTime = TimeSpan.Parse(model.ProviderLeaveEndTime);
                return await this.unitOfWork.ProviderLeaves.UpdateAsync(providerLeave);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <inheritdoc />
        public Task<int> CancelAsync(int? ProviderLeaveId)
        {
            var query = $@"Update ""ProviderLeave"" set ""Active"" = 'false' WHERE ""ProviderLeaveId"" = {ProviderLeaveId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<string> FindDateByProviderLeaveId(int? ProviderLeaveId)
        {
            var query = $@"SELECT ""LeaveDate""::text FROM ""ProviderLeave"" WHERE ""ProviderLeaveId"" = {ProviderLeaveId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }


        /// <inheritdoc />
        public Task<int> CancelAvailabilityAsync(int? ProviderAvailabilityId)
        {
            var query = $@"Update ""ProviderAvailability"" set ""Active"" = 'false' WHERE ""ProviderAvailabilityId"" = {ProviderAvailabilityId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<string> FindDateByProviderAvailabilityId(int? ProviderAvailabilityId)
        {
            var query = $@"SELECT ""AvailableDate""::text  FROM ""ProviderAvailability"" WHERE ""ProviderAvailabilityId"" = {ProviderAvailabilityId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }


        /// <inheritdoc />
        public Task<int> CancelBreakAsync(int? ProviderBreakId)
        {
            var query = $@"Update ""ProviderBreak"" set ""Active"" = 'false' WHERE ""ProviderBreakId"" = {ProviderBreakId}";
            return this.unitOfWork.Current.ExecuteAsync(query);
        }

        public async Task<string> FindDateByProviderBreakId(int? ProviderBreakId)
        {
            var query = $@"SELECT ""BreakDate""::text  FROM ""ProviderBreak"" WHERE ""ProviderBreakId"" = {ProviderBreakId}";
            var response = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return response;
        }
    }
}
