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 Shared.EntityModels;
    using Shared.UserModels.PatientMedication;
    using Shared.UserModels.Laboratory;
    using System.Linq.Expressions;
    using Hims.Shared.UserModels.Labs;

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

        /// <inheritdoc cref="IPatientEncounterService" />
        public PatientEncounterServices(IUnitOfWork unitOfWork) => this.unitOfWork = unitOfWork;

        /// <inheritdoc/>
        public async Task<int> AddPatientMedicationAsync(PatientMedicationHeaderModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            var findOldHeader = await this.unitOfWork.PatientMedicationHeaders.FindAsync(h => h.PatientMedicationHeaderId == model.PatientMedicationHeaderId);

            var patientMedicationHeader = new PatientMedicationHeader
            {
                Active = true,
                AppointmentId = !model.IsAdmission?model.AppointmentId:null,
                AdmissionId = model.IsAdmission?model.AppointmentId:null,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                EncounterType = model.EncounterType
            };
            //UPDATE "Appointment" SET "EncounterType" = 'InternalMedicine', "ModifiedDate" = NOW() AT TIME ZONE 'UTC' WHERE "AppointmentId" = 11954
            if (findOldHeader == null)
            {
                patientMedicationHeader.PatientMedicationHeaderId = await this.unitOfWork.PatientMedicationHeaders.InsertAsync(patientMedicationHeader, transaction);
                if (patientMedicationHeader.PatientMedicationHeaderId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            else
            {
                patientMedicationHeader.PatientMedicationHeaderId = findOldHeader.PatientMedicationHeaderId;
                findOldHeader.ModifiedDate = patientMedicationHeader.CreatedDate;
                findOldHeader.ModifiedBy = patientMedicationHeader.CreatedBy;
                var updateResponse = await this.unitOfWork.PatientMedicationHeaders.UpdateAsync(findOldHeader, transaction);
                if (updateResponse == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }



            var medicationDetails = (model.Medicines.Where(x => x.PatientMedicationDetailId == 0).Select(x => new PatientMedicationDetail
            {
                PatientMedicationHeaderId = patientMedicationHeader.PatientMedicationHeaderId,
                AfternoonDosage = x.AfternoonDosage,
                Duration = x.Duration,
                DurationType = x.DurationType,
                IsAfternoon = x.IsAfternoon,
                IsMorning = x.IsMorning,
                IsNight = x.IsNight,
                MorningDosage = x.MorningDosage,
                NightDosage = x.NightDosage,
                PharmacyProductId = x.PharmacyProductId,
                Dosage = x.Dosage,
                Instruction = x.Instruction,
                Route = x.Route,
                Remark = x.Remark,
            })).ToList();

            if (medicationDetails.Count > 0)
            {
                var detailResponse = await this.unitOfWork.PatientMedicationDetails.BulkInsertAsync(medicationDetails, transaction);
                if (detailResponse == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            var getDetailRecordForUpdate = (model.Medicines.Where(x => x.PatientMedicationDetailId > 0)).ToList();
            if (getDetailRecordForUpdate.Count > 0)
            {
                foreach (var detail in getDetailRecordForUpdate)
                {
                    var getPreviousDetail = await this.unitOfWork.PatientMedicationDetails.FindAsync(d => d.PatientMedicationDetailId == detail.PatientMedicationDetailId);
                    if (getPreviousDetail == null)
                    {
                        transaction.Rollback();
                        return -1;
                    }

#pragma warning disable S2259 // Null pointers should not be dereferenced
                    getPreviousDetail.Instruction = detail.Instruction;
#pragma warning restore S2259 // Null pointers should not be dereferenced
                    getPreviousDetail.Duration = detail.Duration;
                    getPreviousDetail.DurationType = detail.DurationType;
                    getPreviousDetail.AfternoonDosage = detail.AfternoonDosage;
                    getPreviousDetail.IsAfternoon = detail.IsAfternoon;
                    getPreviousDetail.IsMorning = detail.IsMorning;
                    getPreviousDetail.IsNight = detail.IsNight;
                    getPreviousDetail.MorningDosage = detail.MorningDosage;
                    getPreviousDetail.NightDosage = detail.NightDosage;
                    getPreviousDetail.PharmacyProductId = detail.PharmacyProductId;
                    getPreviousDetail.Dosage = detail.Dosage;
                    getPreviousDetail.Route = detail.Route;

                    var detailUpdateResponse = await this.unitOfWork.PatientMedicationDetails.UpdateAsync(getPreviousDetail, transaction);
                    if (detailUpdateResponse == 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            transaction.Commit();

            return patientMedicationHeader.PatientMedicationHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PatientMedicationHeaderModel>> FetchPatientMedication(PatientMedicationHeaderModel model)
        {
            var where = "where 1=1";
            if (model.AppointmentId > 0)
            {
                where += $@" and PMH.""AppointmentId"" = {model.AppointmentId}";
            }
            var headerQuery = model.IsAdmission ?
                $@"  SELECT PMH.""PatientMedicationHeaderId"", PMH.""AdmissionId"", PMH.""CreatedBy"", PMH.""CreatedDate"", PMH.""ModifiedBy"", PMH.""ModifiedDate"", PMH.""Active"", 
		                        INITCAP(PMH.""EncounterType"") as ""EncounterType"", CR.""FullName"" as ""CreatedByName"",MR.""FullName"" as ""ModifiedByName"",A.""AdmissionNo"", 
		                        A.""AdmissionDate""::text,A.""AdmissionTime"" as ""AdmissionTimeString"",P.""PatientId"" ,P.""FullName"" as ""PatientName"",P.""Gender"" as ""PatientGender"",P.""Age"" as ""PatientAge"",
		                        P.""Mobile"" as ""PatientMobile""
                           FROM ""PatientMedicationHeader"" PMH 
                            join ""Account"" CR on CR.""AccountId"" = PMH.""CreatedBy""
                           left join ""Account"" MR ON MR.""AccountId""  = PMH.""ModifiedBy"" 
                           join ""Admission"" A on A.""AdmissionId"" = PMH.""AdmissionId"" 
                            join ""Patient"" P on P.""PatientId"" = A.""PatientId"" 
                            where PMH.""AdmissionId"" = {model.AppointmentId}":
                $@"  SELECT PMH.""PatientMedicationHeaderId"",string_agg(dISTINCT S.""SpecializationName"",', ') ""SpecializationName"",Pr.""Educations"",Pr.""ProviderNo"",s.""SpecializationId""
,Pra.""FullName"" as ""PracticeName"",PrL.""Name"" AS ""PracticeLocation"", PMH.""AppointmentId"", PMH.""CreatedBy"", PMH.""CreatedDate"", PMH.""ModifiedBy"", PMH.""ModifiedDate"", PMH.""Active"", 
		                        INITCAP(PMH.""EncounterType"") as ""EncounterType"", CR.""FullName"" as ""CreatedByName"",MR.""FullName"" as ""ModifiedByName"",A.""AppointmentNo"", 
		                        A.""AppointmentDate""::text,A.""AppointmentTime"" as ""AppointmentTimeString"",P.""PatientId"" ,P.""FullName"" as ""PatientName"",P.""Gender"" as ""PatientGender"",P.""Age"" as ""PatientAge"",
		                        P.""Mobile"" as ""PatientMobile"",Pr.""FullName"" as ""ProviderName"",Pr.""ProviderId"",P.""UMRNo""
								,PraL.""StreetAddress"",PraL.""PracticeId"",c.""CityName"",sta.""StateName"",cont.""CountryName""
                           FROM ""PatientMedicationHeader"" PMH 
                            join ""Account"" CR on CR.""AccountId"" = PMH.""CreatedBy""
                           left join ""Account"" MR ON MR.""AccountId""  = PMH.""ModifiedBy"" 
                           join ""Appointment"" A on A.""AppointmentId"" = PMH.""AppointmentId"" 
                            join ""Patient"" P on P.""PatientId"" = A.""PatientId"" 
                             join ""Provider"" Pr on Pr.""ProviderId"" =A.""ProviderId"" 
                           left JOIN ""ProviderLocation"" PL ON PL.""LocationId"" = A.""LocationId""
						    JOIN ""Specialization"" S ON S.""SpecializationId"" =ANY(Pr.""Specializations"") and S.""SpecializationId"" = A.""SpecializationId""
						    left JOIN ""Location"" PrL ON PrL.""LocationId"" = PL.""LocationId""							
						    left JOIN ""Practice"" Pra ON Pra.""PracticeId"" = PrL.""PracticeId""						 
                        left JOIN ""PracticeLocation"" PraL ON PraL.""LocationId"" =PL.""LocationId""
                    left join ""City"" c on c.""CityId""=PraL.""CityId""
                    left join ""State"" sta on sta.""StateId""=PraL.""StateId"" 
                left join ""Country"" cont on cont.""CountryId""=PraL.""CountryId""
                    {where}
		                    group by pmh.""PatientMedicationHeaderId""
							,Pra.""FullName""
							,PrL.""Name"",cr.""FullName"",MR.""FullName"",A.""AppointmentNo"",A.""AppointmentDate"",A.""AppointmentTime"",P.""PatientId"",Pr.""FullName"",Pr.""ProviderId""
						,PraL.""StreetAddress"",PraL.""PracticeId"",c.""CityName"",sta.""StateName"",cont.""CountryName"",S.""SpecializationId""
							order by PMH.""PatientMedicationHeaderId"" desc";
            var headerResponse = await this.unitOfWork.Current.QueryAsync<PatientMedicationHeaderModel>(headerQuery);

            foreach (var header in headerResponse)
            {
                header.Medicines = new List<PatientMedicationDetailModel>();
                var detailQuery = $@"SELECT distinct PMD.""PatientMedicationDetailId"", PMD.""PatientMedicationHeaderId"", PMD.""PharmacyProductId"", PMD.""Duration"", PMD.""DurationType"", 
		                                    PMD.""IsMorning"", PMD.""IsAfternoon"", PMD.""IsNight"", PMD.""MorningDosage"", PMD.""AfternoonDosage"", PMD.""NightDosage"", PMD.""Dosage"", PMD.""Instruction"",
		                                    PP.""ProductName"",PP.""GenericName"",PP.""CategoryId"", PP.""CompanyId"",C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",
                                            PMD.""Route"", sale.""Name"" as ""SaleUnitName"", PMD.""Remark""
			                                    FROM ""PatientMedicationDetail"" PMD
			                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PMD.""PharmacyProductId"" 
			                                    join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
			                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
                                                join ""LookupValue"" sale on sale.""LookupValueId"" = PP.""SaleUnit""
			                                    where PMD.""PatientMedicationHeaderId"" = {header.PatientMedicationHeaderId}
			                                    order by PP.""ProductName"" asc ";
                header.Medicines = (await this.unitOfWork.Current.QueryAsync<PatientMedicationDetailModel>(detailQuery)).ToList();
            }

            return headerResponse;
        }

        /// <inheritdoc/>
        public async Task<int> DeleteSingleMedicationAsync(PatientMedicationDetailModel model)
        {
            var query = $@"DELETE FROM ""PatientMedicationDetail"" where ""PatientMedicationDetailId"" = {model.PatientMedicationDetailId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }


        /// <inheritdoc/>
        public async Task<int> AddPatientLabAsync(AddBooking model)
        {
            var transaction = this.unitOfWork.BeginTransaction();

            var header = new PatientLabHeader
            {
                Active = true,
                AppointmentId =!model.IsAdmission? model.AppointmentId:null,
                AdmissionId = model.IsAdmission ? model.AppointmentId : null,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                PatientLabHeaderId = model.PatientLabHeaderId
            };
            if (header.PatientLabHeaderId == 0)
            {
                
                    header.PatientLabHeaderId = await this.unitOfWork.PatientLabHeaders.InsertAsync(header, transaction);

                
                if (header.PatientLabHeaderId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            else
            {
                var oldRecordHeader = await this.unitOfWork.PatientLabHeaders.FindAsync(h => h.PatientLabHeaderId == header.PatientLabHeaderId);
                if (oldRecordHeader == null)
                {
                    transaction.Rollback();
                    return -1;
                }
                oldRecordHeader.ModifiedDate = DateTime.Now;
                oldRecordHeader.ModifiedBy = header.CreatedBy;

                var updateResponse = await this.unitOfWork.PatientLabHeaders.UpdateAsync(oldRecordHeader, transaction);
                if (updateResponse == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            var details = model.Labs.Where(x => x.PatientLabDetailId == 0).Select(x => new PatientLabDetail
            {
                PatientLabHeaderId = header.PatientLabHeaderId,
                LabMainDetailId = (int)(x.LabMainDetailId == 0 ? (int?)null : x.LabMainDetailId)
            }).ToList();

            if (details.Count > 0)
            {
                var detailResponse = await this.unitOfWork.PatientLabDetails.BulkInsertAsync(details, transaction);
                if (detailResponse == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            transaction.Commit();
            return header.PatientLabHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PatientMedicationHeaderModel>> FetchPatientLabsAsync(PatientMedicationHeaderModel model)
        {
            var where = "where 1=1";
            if (model.AppointmentId > 0)
            {
                if(model.IsAdmission)
                {
                    where += $@"  and PLH.""AdmissionId"" = {model.AppointmentId}";

                }
                else
                {
                    where += $@"  and PLH.""AppointmentId"" = {model.AppointmentId}";

                }
            }

            var checkBilling = await this.unitOfWork.NewLabBookingHeaders.FindAsync(x => x.AppointmentId == model.AppointmentId);
            if (checkBilling != null)
            {
                var demo = new List<PatientMedicationHeaderModel>();
                var demoData = new PatientMedicationHeaderModel { IsBillingDone = true, RequisitionNumber = checkBilling.RequisitionNumber, Labs = new List<LabMainDetailModel>() };
                demo.Add(demoData);
                return demo;
            }                                              

            var headerQuery =model.IsAdmission?
                $@"select DISTINCT (PLH.""PatientLabHeaderId""),PLH.""AdmissionId"",Pr.""ProviderNo"",PrL.""Name"" AS ""PracticeLocation"",
                                            PLH.""CreatedBy"", PLH.""CreatedDate"", PLH.""ModifiedBy"", PLH.""ModifiedDate"", PLH.""Active"",Pra.""FullName"" as ""PracticeName"",
                                     CR.""FullName"" as ""CreatedByName"",MR.""FullName"" as ""ModifiedByName"",A.""AdmissionNo"",Pr.""Educations"",
                                               A.""AdmissionDate""::text,A.""AdmissionTime""::text,P.""PatientId"" ,P.""FullName"" as ""PatientName"",P.""Gender"" as ""PatientGender"",
                                     P.""Age"" as ""PatientAge"",P.""Mobile"" as ""PatientMobile"",Pr.""FullName"" as ""ProviderName"",Pr.""ProviderId"",P.""UMRNo""
                                              from ""PatientLabHeader"" PLH
                                          join ""Admission"" A on A.""AdmissionId"" = PLH.""AdmissionId""
                                     join ""Provider"" Pr on Pr.""ProviderId"" =A.""ProviderId""
                                          JOIN ""Location"" PrL ON PrL.""LocationId"" = A.""LocationId""
                                          join ""Account"" CR on CR.""AccountId"" = PLH.""CreatedBy""
                                      left join ""Account"" MR ON MR.""AccountId""  = PLH.""ModifiedBy""
                               join ""Patient"" P on P.""PatientId"" = A.""PatientId""
                                                  JOIN ""Practice"" Pra ON Pra.""PracticeId"" = PrL.""PracticeId""
                                          {where}":
                $@"select DISTINCT (PLH.""PatientLabHeaderId""),PLH.""AppointmentId"",Pr.""ProviderNo"",PrL.""Name"" AS ""PracticeLocation"",string_agg(S.""SpecializationName"",', ') ""SpecializationName"",
                                            PLH.""CreatedBy"", PLH.""CreatedDate"", PLH.""ModifiedBy"", PLH.""ModifiedDate"", PLH.""Active"",Pra.""FullName"" as ""PracticeName"",
                                     CR.""FullName"" as ""CreatedByName"",MR.""FullName"" as ""ModifiedByName"",A.""AppointmentNo"",Pr.""Educations"",
                                               A.""AppointmentDate""::text,A.""AppointmentTime""::text,P.""PatientId"" ,P.""FullName"" as ""PatientName"",P.""Gender"" as ""PatientGender"",
                                     P.""Age"" as ""PatientAge"",P.""Mobile"" as ""PatientMobile"",Pr.""FullName"" as ""ProviderName"",Pr.""ProviderId"",P.""UMRNo""
                                              from ""PatientLabHeader"" PLH
                                          join ""Appointment"" A on A.""AppointmentId"" = PLH.""AppointmentId""
                                     join ""Provider"" Pr on Pr.""ProviderId"" =A.""ProviderId""
                                          JOIN ""Location"" PrL ON PrL.""LocationId"" = A.""LocationId""
                                          join ""Account"" CR on CR.""AccountId"" = PLH.""CreatedBy""
                                      left join ""Account"" MR ON MR.""AccountId""  = PLH.""ModifiedBy""
                               join ""Patient"" P on P.""PatientId"" = A.""PatientId""
                                                  JOIN ""Practice"" Pra ON Pra.""PracticeId"" = PrL.""PracticeId""
                                    JOIN ""Specialization"" S ON S.""SpecializationId"" =ANY(Pr.""Specializations"") and S.""SpecializationId"" = A.""SpecializationId""
                                          {where} group by PLH.""PatientLabHeaderId"",PrL.""Name"",
                                      Pr.""ProviderNo"",Pra.""FullName"",CR.""FullName"",MR.""FullName"",A.""AppointmentNo"",
                                       Pr.""Educations"",A.""AppointmentDate"",A.""AppointmentTime"",P.""PatientId"",Pr.""FullName"",Pr.""ProviderId"",P.""UMRNo""
                                     order by  PLH.""PatientLabHeaderId"" desc";

            var headerResponse = await this.unitOfWork.Current.QueryAsync<PatientMedicationHeaderModel>(headerQuery);

            foreach (var item in headerResponse)
            {
                item.Labs = new List<LabMainDetailModel>();
                var getAllLabs = (await this.unitOfWork.PatientLabDetails.FindAllAsync(x => x.PatientLabHeaderId == item.PatientLabHeaderId)).ToList();

                if (getAllLabs.Count > 0)
                {
                    var labQuery = $@"SELECT count(LMD.*) over() as ""TotalItems"", LMD.""LabMainDetailId"", LMD.""TestCode"", LMD.""TestName"", LMD.""Active"", LMD.""CreatedBy"", LMD.""CreatedDate"", LMD.""ModifiedBy"", LMD.""ModifiedDate"",
                                  A.""FullName"" as ""CreatedByName"", M.""FullName"" as ""ModifiedByName"",LD.""LabDepartmentId"",LD.""DepartmentName"",pld.""PatientLabDetailId""
                                  FROM ""LabMainDetail"" LMD
                                  join ""LabDepartment"" LD on LD.""LabDepartmentId"" = LMD.""LabDepartmentId"" and LD.""Active"" is true
                                  join ""Account"" A on A.""AccountId"" = LMD.""CreatedBy"" 
                                  join ""PatientLabDetail"" pld on pld.""LabMainDetailId"" = LMD.""LabMainDetailId""
                                     left join ""Account"" M on M.""AccountId"" = LMD.""ModifiedBy"" 
                                     where LMD.""LabMainDetailId"" in ({string.Join(",", getAllLabs.Select(x => x.LabMainDetailId))}) and pld.""PatientLabHeaderId"" = {item.PatientLabHeaderId}
                                          order by LMD.""CreatedDate"" desc";
                    var labs = (await this.unitOfWork.Current.QueryAsync<LabMainDetailModel>(labQuery)).ToList();
                    item.Labs.AddRange(labs);
                }
            }

            return headerResponse;
        }

        /// <inheritdoc/>
        public async Task<int> DeleteSingleLabAsync(PatientMedicationDetailModel model)
        {
            var query = $@"DELETE FROM ""PatientLabDetail"" where ""PatientLabDetailId"" = {model.PatientLabDetailId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> VerifyLabReportWithoutPackageAsync(int labBookingDetailId, int verifiedBy)
        {
            var bookingDetail = await this.unitOfWork.LabBookingDetails.FindAsync(m => m.LabBookingDetailId == labBookingDetailId);
            bookingDetail.IsReportGenerated = true;
            bookingDetail.ReportDate = DateTime.UtcNow.AddMinutes(330);
            bookingDetail.Status = "Report Generated";
            bookingDetail.VerifiedByDoctorId = verifiedBy;
            return await this.unitOfWork.LabBookingDetails.UpdateAsync(bookingDetail);
        }

        /// <inheritdoc/>
        public async Task<int> VerifyLabBookingPackageAsync(int verifiedBy, int? labBookingDetailId, int? labBookingPackageDetailId)
        {
            var where = " where 1=1";
            var flagPackage = false;
            if (labBookingDetailId != null && labBookingPackageDetailId == null)
            {
                where += $@" and ""LabBookingDetailId"" = {labBookingDetailId}";
                await this.VerifyLabReportWithoutPackageAsync((int)labBookingDetailId, verifiedBy);
            }
            else
            {
                where += $@" and ""LabBookingPackageDetailId"" = {labBookingPackageDetailId}";
                flagPackage = true;
            }

            var query = $@"UPDATE ""LabBookingPackageDetail"" SET ""Status""='Report Generated', ""IsReportGenerated""= true, 
                                ""ReportDate""='{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}', ""VerifiedByDoctorId""={verifiedBy} {where}";
            var response = await this.unitOfWork.Current.ExecuteAsync(query);
            if (flagPackage)
            {
                var (flag, labId) = await this.CheckStatusForReportUpdateAsync((int)labBookingPackageDetailId);
                if (flag)
                {
                    await this.VerifyLabReportWithoutPackageAsync(labId, verifiedBy);
                }
            }
            return response;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabMainDetailModel>> FetchFrequentlyUsedLabsAsync(LabMainDetailModel model)
        {
            var where = "where 1=1";
            if (model.CreatedBy != null)
            {
                where += $@" and  plh.""CreatedBy"" = {model.CreatedBy}";
            }

            if (!string.IsNullOrEmpty(model.Term))
            {
                where += $@" and (lower(LMD.""TestName"") ilike '%{model.Term.ToLower()}%' or lower(LMD.""TestCode"") ilike '%{model.Term.ToLower()}%')";
            }


            var query = $@"with data as(select distinct  LMD.""LabMainDetailId"", LMD.""TestCode"", LMD.""TestName"",plh.""CreatedDate"" ,LD.""DepartmentName""
                               FROM ""LabMainDetail"" LMD
                               join ""LabDepartment"" LD on LD.""LabDepartmentId"" = LMD.""LabDepartmentId"" and LD.""Active"" is true                                  
                               join ""PatientLabDetail"" pld on pld.""LabMainDetailId"" = LMD.""LabMainDetailId""
                               join ""PatientLabHeader"" plh on plh.""PatientLabHeaderId"" = pld.""PatientLabHeaderId"" 
                               {where}
                               order by plh.""CreatedDate""  desc)       
                               select distinct  d.""LabMainDetailId"", d.""TestCode"", d.""TestName"",d.""DepartmentName"" from data d
                               limit 25 offset 0";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<PatientMedicationDetailModel>> FetchFrequentlyUsedMedications(PatientMedicationDetailModel model)
        {
            var where = "where 1=1";
            if (model.CreatedBy != null)
            {
                where += $@" and pmh.""CreatedBy"" = {model.CreatedBy}";
            }

            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and lower(PP.""ProductName"") ilike '%{model.ProductName.ToLower()}%'";
            }

            var query = $@"SELECT distinct  PMD.""PharmacyProductId"",  PP.""ProductName"",PP.""GenericName"", PMD.""Duration"", PMD.""DurationType"", 
		                             PMD.""IsMorning"", PMD.""IsAfternoon"", PMD.""IsNight"", PMD.""MorningDosage"", PMD.""AfternoonDosage"", PMD.""NightDosage"", PMD.""Dosage"", PMD.""Instruction"",
		                             PP.""CategoryId"", PP.""CompanyId"",C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",
    	                             PMD.""Route"", sale.""Name"" as ""SaleUnitName"",pmh.""CreatedDate"" 
	                            FROM ""PatientMedicationDetail"" PMD
	                            join ""PatientMedicationHeader"" pmh ON pmh.""PatientMedicationHeaderId"" = PMD.""PatientMedicationHeaderId""  
	                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PMD.""PharmacyProductId"" 
	                            join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                            join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
                                join ""LookupValue"" sale on sale.""LookupValueId"" = PP.""SaleUnit""
	                            {where}
	                            order by pmh.""CreatedDate"" desc limit 25 offset 0";
            return await this.unitOfWork.Current.QueryAsync<PatientMedicationDetailModel>(query);
        }

        /// <summary>
        /// The check status for report update async.
        /// </summary>
        /// <param name="labBookingPackageDetailId">
        /// The lab booking package detail id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        private async Task<Tuple<bool, int>> CheckStatusForReportUpdateAsync(int labBookingPackageDetailId)
        {
            var response = await this.unitOfWork.LabBookingPackageDetails.FindAsync(m => m.LabBookingPackageDetailId == labBookingPackageDetailId);
            if (response == null)
            {
                return Tuple.Create(false, 0);
            }
            var labBookingId = response.LabBookingDetailId;
            var fetchAllPackageLabs = (await this.unitOfWork.LabBookingPackageDetails.FindAllAsync(m => m.LabBookingDetailId == labBookingId)).ToList();
            if (fetchAllPackageLabs.Count > 0)
            {
                var isAnyRecordMissing = (fetchAllPackageLabs.Where(m => m.VerifiedByDoctorId == (int?)null)).ToList();
                if (isAnyRecordMissing.Count > 0)
                {
                    return Tuple.Create(false, 0);
                }
                else
                {
                    return Tuple.Create(true, labBookingId);
                }
            }
            return Tuple.Create(false, 0);
        }

    }
}