using System.Linq;

namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Domain.Configurations;
    using Hims.Shared.DataFilters;
    using Shared.EntityModels;
    using Shared.UserModels.Laboratory;
    using Hims.Shared.UserModels.ServiceOrder;

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

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

        /// <inheritdoc cref="IRoleService" />
        public LaboratoryServices(IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration)
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
        }

        /// <inheritdoc/>
        public async Task<int> CreateUnitAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                var lookup = await this.unitOfWork.Lookups.FindAsync(m => m.Name == "LaboratoryUnit");
                if (lookup == null)
                {
                    var lookupModel = new Lookup { Name = "LaboratoryUnit", Description = "Laboratory Units types." };
                    model.LookupId = await this.unitOfWork.Lookups.InsertAsync(lookupModel);
                }
                else
                {
                    model.LookupId = lookup.LookupId;
                }
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedBy = model.LoginAccountId,
                CreatedDate = DateTime.Now
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }

        /// <inheritdoc/>
        public async Task<int> ModifyLabAsync(LabHeaderModel model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var labHeader = new LabHeader
                {
                    LabHeaderId = model.LabHeaderId,
                    Active = true,
                    Charge = model.Charge,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    LabCode = model.LabCode,
                    LabName = model.LabName,
                    Signature = model.Signature,
                    // InPatientCharge = model.InPatientCharge,
                    LabDepartmentId = model.LabDepartmentId
                };

                if (model.LabHeaderId > 0)
                {
                    var checkIfQuery = $@"SELECT count(""LabHeaderId"")	FROM ""LabHeader"" where lower(""LabName"") = '{model.LabName.ToLower()}' and ""LabHeaderId"" <> {model.LabHeaderId} ";
                    var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                    if (checkIf > 0)
                    {
                        return -2;
                    }

                    var savedRecord = await this.unitOfWork.LabHeaders.FindAsync(m => m.LabHeaderId == model.LabHeaderId);
                    savedRecord.Charge = model.Charge;
                    savedRecord.LabCode = model.LabCode;
                    savedRecord.LabName = model.LabName;
                    savedRecord.Signature = model.Signature;
                    savedRecord.ModifiedBy = model.CreatedBy;
                    savedRecord.ModifiedDate = DateTime.Now;
                    // savedRecord.InPatientCharge = model.InPatientCharge;
                    savedRecord.LabDepartmentId = model.LabDepartmentId;

                    var headerResponse = await this.unitOfWork.LabHeaders.UpdateAsync(savedRecord, transaction);
                    if (headerResponse <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }

                    var locationMapRecord = await this.unitOfWork.LocationLabHeaderMap.FindAsync(m => (m.LocationId == model.LocationId &&
                      m.LabHeaderId == model.LabHeaderId));
                    locationMapRecord.Charge = (decimal)model.Charge;
                    locationMapRecord.InPatientCharge = (decimal)model.InPatientCharge;
                    locationMapRecord.ModifiedBy = model.CreatedBy;
                    locationMapRecord.ModifiedDate = DateTime.Now;

                    var headerLocationMapResponse = await this.unitOfWork.LocationLabHeaderMap.UpdateAsync(locationMapRecord, transaction);
                    if (headerLocationMapResponse <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }


                }
                else
                {
                    var checkIfQuery = $@"SELECT count(""LabHeaderId"")	FROM ""LabHeader"" where lower(""LabName"") = '{model.LabName.ToLower()}'";
                    var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                    if (checkIf > 0)
                    {
                        return -2;
                    }

                    labHeader.LabHeaderId = await this.unitOfWork.LabHeaders.InsertAsync(labHeader, transaction);
                    if (labHeader.LabHeaderId <= 0)
                    {
                        transaction.Rollback();
                        return -2;
                    }
                    var locationHeaderMap = new LocationLabHeaderMap
                    {
                        InPatientCharge = (decimal)model.InPatientCharge,
                        Charge = (decimal)model.Charge,
                        LabHeaderId = labHeader.LabHeaderId,
                        LocationId = model.LocationId,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        IsActive = true
                    };
                    try
                    {
                        locationHeaderMap.LocationLabHeaderMapId = await this.unitOfWork.LocationLabHeaderMap.InsertAsync(locationHeaderMap, transaction);
                        if (locationHeaderMap.LocationLabHeaderMapId <= 0)
                        {
                            transaction.Rollback();
                            return -2;
                        }
                    }
                    catch (Exception e) { return 0; }
                }

                var findPreviousParameters = (await this.unitOfWork.LabDetails.FindAllAsync(m => m.LabHeaderId == model.LabHeaderId)).ToList();
                if (findPreviousParameters.Count > 0)
                {
                    var missingRecords = findPreviousParameters.Where(item => model.LabDetails.All(inputList => inputList.LabDetailId != item.LabDetailId));
                    var listedRecord = missingRecords.ToList();
                    if (listedRecord.Count > 0)
                    {
                        var ids = string.Join(",", listedRecord.Select(item => item.LabDetailId.ToString()));
                        var lapPatientDeleteQuery = $@"Delete from ""LabPatientParameter"" where ""LabDetailId"" in ({ids})";
                        var query = $@"Delete from ""LabDetail"" where ""LabDetailId"" in ({ids})";
                        try
                        {
                            await this.unitOfWork.Current.ExecuteAsync(lapPatientDeleteQuery, transaction);
                            await this.unitOfWork.Current.ExecuteAsync(query, transaction);
                        }
                        catch (Exception ex)
                        {
                            // ignore
                        }
                    }
                }

                foreach (var detail in model.LabDetails)
                {
                    var labDetail = new LabDetail
                    {
                        Active = true,
                        LabHeaderId = labHeader.LabHeaderId,
                        ReferenceRange = detail.ReferenceRange,
                        RefrenceRangeUnit = detail.RefrenceRangeUnit,
                        TestParameter = detail.TestParameter
                    };

                    if (detail.LabDetailId > 0)
                    {
                        labDetail.LabDetailId = detail.LabDetailId;
                        var detailResponse = await this.unitOfWork.LabDetails.UpdateAsync(labDetail, transaction);
                        if (detailResponse <= 0)
                        {
                            transaction.Rollback();
                            return -3;
                        }
                    }
                    else
                    {
                        labDetail.LabDetailId = await this.unitOfWork.LabDetails.InsertAsync(labDetail, transaction);
                        if (labDetail.LabDetailId <= 0)
                        {
                            transaction.Rollback();
                            return -4;
                        }
                    }
                }
                transaction.Commit();
                return labHeader.LabHeaderId;
            }
        }


        /// <inheritdoc/>
        public async Task<IEnumerable<LabHeaderModel>> FetchAllLabs(RequestLaboratory model)
        {
            var where = " where 1=1 ";

            if (!string.IsNullOrEmpty(model.LabName))
            {
                where += $@" and LH.""LabName"" ilike '%{model.LabName}%' ";
            }
            if (model.LocationId > 0)
            {
                // where += $@" and  LHM.""LocationId"" ={model.LocationId} ";
            }

            if (!string.IsNullOrEmpty(model.LabCode))
            {
                where += $@" and LH.""LabCode"" ilike '%{model.LabCode}%' ";
            }

            // where += $@" and LHM.""ChargeCategoryId"" = (select ""ChargeCategoryId"" from ""ChargeCategory"" where lower(""ChargeCategoryName"") = 'general')";

            var query = $@"SELECT count(LH.*) over() as ""TotalItems"", LH.""Charge"",LH.""LabHeaderId"", LH.""LabCode"", LH.""Signature"", LH.""LabName"", LH.""Active"", LH.""CreatedBy"", LH.""CreatedDate"", LH.""ModifiedBy"", LH.""ModifiedDate"",
	                        (Select count(*) from ""LabDetail"" where ""LabHeaderId"" = LH.""LabHeaderId"") as  ""NoOfParameter"", A.""FullName"" as ""CreatedByName"",
							M.""FullName"" as ""ModifiedByName"",LD.""LabDepartmentId"",LD.""DepartmentName""
	                        FROM ""LabHeader"" LH 
                            join ""LabDepartment"" LD on LD.""LabDepartmentId"" = LH.""LabDepartmentId"" and LD.""Active"" is true
	                        join ""Account"" A on A.""AccountId"" = LH.""CreatedBy"" 
                            left join ""Account"" M on M.""AccountId"" = LH.""ModifiedBy"" 
                            --join ""LocationLabHeaderMap"" LHM on LHM.""LabHeaderId"" = LH.""LabHeaderId"" 
                            {where} order by LH.""CreatedDate"" desc ";

            if (model.PageIndex == null || model.PageSize == null)
            {
                return await this.unitOfWork.Current.QueryAsync<LabHeaderModel>(query);
            }

            model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
            query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<LabHeaderModel>> FetchImportLabs(RequestLaboratory model)
        {
            var where = " where 1=1 ";

            if (!string.IsNullOrEmpty(model.LabName))
            {
                where += $@" and LH.""LabName"" ilike '%{model.LabName}%' ";
            }
            if (model.LocationId > 0)
            {
                where += $@" and  LHM.""LocationId"" NOt IN ({model.LocationId}) ";
            }

            if (!string.IsNullOrEmpty(model.LabCode))
            {
                where += $@" and LH.""LabCode"" ilike '%{model.LabCode}%' ";
            }


            var query = $@"SELECT count(LH.*) over() as ""TotalItems"", LHM.""InPatientCharge"",l.""Name"" as ""LocationName"",LH.""LabHeaderId"", LH.""LabCode"", LH.""Signature"", LH.""LabName"", LHM.""Charge"", LH.""Active"", LH.""CreatedBy"", LH.""CreatedDate"", LH.""ModifiedBy"", LH.""ModifiedDate"",
	                        (Select count(*) from ""LabDetail"" where ""LabHeaderId"" = LH.""LabHeaderId"") as  ""NoOfParameter"", 
							LD.""LabDepartmentId"",LD.""DepartmentName""
	                        FROM ""LabHeader"" LH 
                            join ""LabDepartment"" LD on LD.""LabDepartmentId"" = LH.""LabDepartmentId"" and LD.""Active"" is true
                            join ""LocationLabHeaderMap"" LHM on LHM.""LabHeaderId"" = LH.""LabHeaderId"" 
							join ""Location"" l on l.""LocationId"" = LHM.""LocationId""


                            {where} and LHM.""LabHeaderId"" not in (select ""LabHeaderId"" from ""LocationLabHeaderMap"" where ""LocationId"" = {model.LocationId})order by LH.""CreatedDate"" desc ";

            if (model.PageIndex == null || model.PageSize == null)
            {
                return await this.unitOfWork.Current.QueryAsync<LabHeaderModel>(query);
            }

            model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
            query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";

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

        /// <inheritdoc/>
        public async Task<IEnumerable<LabDetailModel>> FetchLabDetails(int id)
        {
            var query = $@"SELECT LB.""LabDetailId"", LB.""LabHeaderId"", LB.""TestParameter"", LB.""ReferenceRange"", LB.""RefrenceRangeUnit"", LB.""Active"",LV.""Name""
	                            FROM ""LabDetail"" LB 
	                            left join ""LookupValue"" LV on LV.""LookupValueId"" =  LB.""RefrenceRangeUnit"" 
	                            where LB.""LabHeaderId"" = {id}";
            return await this.unitOfWork.Current.QueryAsync<LabDetailModel>(query);
        }
        /// <inheritdoc/>
        public async Task<IEnumerable<LabDetailModel>> FetchLabName(int id)
        {
            var query = $@"SELECT LB.""LabDetailId"", LB.""LabHeaderId"", LB.""TestParameter"", LB.""ReferenceRange"", LB.""RefrenceRangeUnit"", LB.""Active"",LV.""Name""
	                            FROM ""LabDetail"" LB 
	                            left join ""LabBookingDetail"" LV on LV.""LabBookingDetailId"" =  LB.""LabBookingDetailId"" 
	                            where LB.""LabHeaderId"" = {id}";
            return await this.unitOfWork.Current.QueryAsync<LabDetailModel>(query);
        }
        /// <inheritdoc/>
        public async Task<int> DeleteLabsAsync(int id, int locationId)
        {

            var query = $@"DELETE FROM ""LocationLabHeaderMap"" WHERE ""LabHeaderId"" = {id} AND ""LocationId""={locationId}";
                          // DELETE FROM ""LabDetail"" WHERE ""LabHeaderId"" = {id};
                          //DELETE FROM ""LabHeader""	WHERE ""LabHeaderId"" = {id}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> AddPatientLabBooking(AddBooking model, List<InsertLabServiceHelperModel> labServicesFromServiceOrder)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var bookingHeader = new LabBookingHeader
                {
                    BillNumber = await this.GetBillNumber(),
                    BookingDate = DateTime.Now,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    DoctorName = model.DoctorName,
                    NetAmount = model.NetAmount,
                    //PaidVia = model.PaidVia,
                    PatientId = model.PatientId,
                    PatientName = model.PatientName,
                    PatientType = model.PatientType,
                    Mobile = model.Mobile,
                    OverallDiscount = model.DiscountAmount,
                    TotalAmount = model.Amount,
                    OverallDiscountPercentage = model.DiscountPercentage,
                    Active = true,
                    ProviderId = model.ProviderId,
                    AdmissionId = model.AdmissionId,
                    AppointmentId = model.AppointmentId,
                    Notes = model.Notes,
                    LocationId = model.LocationId,
                    PayTypeId = model.PayTypeId,
                    PaymentNumber = model.PaymentNumber
                };
                bookingHeader.LabBookingHeaderId = await this.unitOfWork.LabBookingHeaders.InsertAsync(bookingHeader, transaction);
                if (bookingHeader.LabBookingHeaderId <= 0)
                {
                    transaction.Rollback();
                    return -2;
                }

                if (labServicesFromServiceOrder.Count > 0)
                {
                    var labDetails = new List<LabHeaderModel>();
                    foreach (var lab in labServicesFromServiceOrder)
                    {
                        var labServiceRecord = new LabServices
                        {
                            Active = true,
                            CreatedDate = DateTime.Now,
                            CreatedBy = model.CreatedBy,
                            AdmissionId = model.AdmissionId,
                            AppointmentId = model.AppointmentId,
                            Cost = lab.Cost,
                            //LabHeaderId = lab.LabHeaderId,
                            Unit = lab.Unit,
                            Notes = lab.Notes
                        };

                        labServiceRecord.LabServicesId = await this.unitOfWork.LabServices.InsertAsync(labServiceRecord);

                        labDetails.Add(new LabHeaderModel
                        {
                            DiscountAmount = 0,
                            DiscountPercentage = 0,
                            NetAmount = 0,
                            LabPackageId = null,
                            LabHeaderId = lab.LabHeaderId,
                            LabServicesId = labServiceRecord.LabServicesId,
                            LabDate = lab.LabDate
                        });
                    }
                    //model.Labs = labDetails;
                }

                //foreach (var lab in model.Labs)
                //{
                //    var isPackageDetail = false;

                //    var bookingDetail = new LabBookingDetail
                //    {
                //        LabBookingHeaderId = bookingHeader.LabBookingHeaderId,
                //        Amount = lab.Charge,
                //        Status = model.Status,
                //        DiscountAmount = lab.DiscountAmount,
                //        DiscountPercentage = lab.DiscountPercentage,
                //        NetAmount = lab.NetAmount,
                //        LabServicesId = lab.LabServicesId,
                //        LabDate = lab.LabDate ?? DateTime.Now
                //    };

                //    if (lab.LabPackageId != null)
                //    {
                //        isPackageDetail = true;
                //        bookingDetail.LabPackageId = lab.LabPackageId;
                //        bookingDetail.LabHeaderId = null;
                //    }
                //    else
                //    {
                //        isPackageDetail = false;
                //        bookingDetail.LabPackageId = null;
                //        bookingDetail.LabHeaderId = lab.LabHeaderId;
                //    }

                //    if (bookingDetail.Status == "Sample collected")
                //    {
                //        bookingDetail.IsSampleCollected = true;
                //        bookingDetail.SampleDate = DateTime.UtcNow.AddMinutes(330);
                //    }

                //    bookingDetail.LabBookingDetailId = await this.unitOfWork.LabBookingDetails.InsertAsync(bookingDetail, transaction);
                //    if (bookingDetail.LabBookingDetailId <= 0)
                //    {
                //        transaction.Rollback();
                //        return -3;
                //    }

                //    if (isPackageDetail)
                //    {
                //        var labsInPackage = (await this.unitOfWork.LabPackageDetails.FindAllAsync(m => m.LabPackageId == lab.LabPackageId)).ToList();
                //        if (labsInPackage.Count > 0)
                //        {
                //            var bookingLabs = labsInPackage.Select(m => new LabBookingPackageDetail
                //            {
                //                LabHeaderId = m.LabHeaderId,
                //                LabBookingDetailId = bookingDetail.LabBookingDetailId,
                //                Status = bookingDetail.Status
                //            });

                //            var responseOfPackageBooking = await this.unitOfWork.LabBookingPackageDetails.BulkInsertAsync(bookingLabs, transaction);
                //            if (responseOfPackageBooking == 0)
                //            {
                //                transaction.Rollback();
                //                return -4;
                //            }
                //        }
                //    }
                //}

                transaction.Commit();
                return bookingHeader.LabBookingHeaderId;
            }
        }

        /// <inheritdoc/>
        public async Task<LabBookingHeaderModel> FetchLabHeadersBasedOnCondition(int? id, string billNumber)
        {
            var where = "where 1=1";

            if (id != null)
            {
                where += $@" and LBH.""LabBookingHeaderId""  = {id}";
            }

            if (!string.IsNullOrEmpty(billNumber))
            {
                where += $@" and LBH.""BillNumber"" = '{billNumber}' ";
            }

            var query = $@"SELECT LBH.""PatientName"", P.""Mobile"", P.""Gender"",P.""Age"", P.""UMRNo"",LBH.""BillNumber"", LBH.""CreatedDate"",LBH.""DoctorName"",
			                        LBH.""LabBookingHeaderId"", LBH.""PatientType"", LBH.""PatientId"", 
                                    LBH.""NetAmount"",LBH.""OverallDiscount"", LBH.""TotalAmount"",PT.""PayTypeName"" as ""PaidVia"", LBH.""CreatedBy"", LBH.""BookingDate"",
                                    A.""FullName"" as ""CreatedByName""
	                                     FROM ""LabBookingHeader"" LBH
	                                     join ""Account"" A on A.""AccountId"" = LBH.""CreatedBy"" 
				                         left join ""Patient"" P on P.""PatientId"" = LBH.""PatientId""	 
                                           left join ""PayType"" PT on PT.""PayTypeId""=LBH.""PayTypeId""
	                                     {where}";

            var bookingHeader = await this.unitOfWork.Current.QuerySingleAsync<LabBookingHeaderModel>(query);

            var bookingDetail = await this.FetchBookingLabDetailsWithPackageDataAsync(bookingHeader.LabBookingHeaderId, null);

            bookingHeader.LabDetail = bookingDetail.ToList();

            return bookingHeader;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabBookingHeaderModel>> FetchLabBookingHeaders(RequestLaboratory model)
        {
            var where = $@"where 1=1 and LBH.""Active"" is true ";
            if (model.FromDate != null)
            {
                where += $@" and LBH.""BookingDate""::date >= '{model.FromDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.ToDate != null)
            {
                where += $@" and LBH.""BookingDate""::date <= '{model.ToDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.PatientId != null)
            {
                where += $@" and LBH.""PatientId"" = '{model.PatientId}'";
            }

            if (model.DoctorName != null)
            {
                where += $@" and LBH.""DoctorName"" =  '{model.DoctorName}'";
            }

            if (model.BillNumber != null)
            {
                where += $@" and LBH.""BillNumber""  ilike '%{model.BillNumber}%'";
            }

            if (model.AccountId != null)
            {
                where += $@" and LBH.""CreatedBy"" = '{model.AccountId}'";
            }
            if (model.UMRNo != null)
            {
                where += $@" and  pa.""UMRNo"" ilike '%{model.UMRNo}%'";
            }
            if (model.Mobile != null)
            {
                where += $@" and  LBH.""Mobile"" = '{model.Mobile}'";
            }
            if (model.LabBookingHeaderId != null)
            {
                where += $@" and LBH.""LabBookingHeaderId"" = {model.LabBookingHeaderId}";
            }
            if (model.LocationId != null)
            {
                where += $@" and LBH.""LocationId"" = {model.LocationId}";
            }

            var query = $@"SELECT  count(LBH.*) over() as ""TotalItems"",LBH.""AdmissionId"",LBH.""AppointmentId"",ad.""AdmissionNo"", ap.""AppointmentNo"" ,LBH.""LabBookingHeaderId"", LBH.""PatientType"", LBH.""BillNumber"", LBH.""PatientId"", LBH.""PatientName"",pa.""Age"",pa.""UMRNo"",pa.""Gender"", LBH.""Mobile"", 
                            LBH.""DoctorName"", LBH.""NetAmount"", PT.""PayTypeName"" as ""PaidVia"", LBH.""CreatedBy"", LBH.""CreatedDate"", LBH.""BookingDate"",
                            A.""FullName"" as ""CreatedByName"",(Select count(*) from ""LabBookingDetail"" where ""LabBookingHeaderId"" = LBH.""LabBookingHeaderId"")  ""NoOfTest"",
                             (CASE WHEN pa.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pa.""Guid"", '/', pa.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl""
	                            ,L.""Name"" as ""LocationName""

                                FROM ""LabBookingHeader"" LBH
                                left join ""Admission"" ad on ad.""AdmissionId"" = LBH.""AdmissionId""
                                left join ""Appointment"" ap on ap.""AppointmentId"" = LBH.""AppointmentId""
                                join ""Account"" A on A.""AccountId"" = LBH.""CreatedBy"" 

                                join ""Patient"" pa on LBH.""PatientId"" = pa.""PatientId"" 
                                Left join ""PayType"" PT on PT.""PayTypeId""=LBH.""PayTypeId""
                                    join ""Location"" L on L.""LocationId""=LBH.""LocationId""
                                {where}
	                            order by LBH.""CreatedDate"" desc";
            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

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

        /// <inheritdoc/>
        public async Task<IEnumerable<LabBookingHeaderModel>> FetchSampleStatus(RequestLaboratory model)
        {
            var status = $@" ";
            if (model.Status != null)
            {
                status = $@"where ""Status"" ilike '%{model.Status}%'";
            }
            var where = $@"where 1=1 and LBH.""LabBookingHeaderId"" in (select ""LabBookingHeaderId"" from ""LabBookingDetail"" {status})";

            if (model.FromDate != null)
            {
                where += $@" and LBH.""BookingDate""::date >= '{model.FromDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.ToDate != null)
            {
                where += $@" and LBH.""BookingDate""::date <= '{model.ToDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.PatientId != null)
            {
                where += $@" and LBH.""PatientId"" = '{model.PatientId}'";
            }

            if (model.ProviderId != null)
            {
                where += $@" and LBH.""ProviderId"" =  '{model.ProviderId}'";
            }

            if (model.BillNumber != null)
            {
                where += $@" and LBH.""BillNumber""  ilike '%{model.BillNumber}%'";
            }

            if (model.AccountId != null)
            {
                where += $@" and LBH.""CreatedBy"" = '{model.AccountId}'";
            }
            if (model.UMRNo != null)
            {
                where += $@" and  pa.""UMRNo"" ilike '%{model.UMRNo}%'";
            }
            if (model.Mobile != null)
            {
                where += $@" and  LBH.""Mobile"" = '{model.Mobile}'";
            }

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

            var query = $@"SELECT  count(LBH.*) over() as ""TotalItems"",LBH.""AdmissionId"",LBH.""AppointmentId"",ad.""AdmissionNo"", ap.""AppointmentNo"" ,LBH.""LabBookingHeaderId"", LBH.""PatientType"", LBH.""BillNumber"", LBH.""PatientId"", LBH.""PatientName"",pa.""Age"",pa.""UMRNo"",pa.""Gender"", LBH.""Mobile"", 
                            LBH.""DoctorName"", LBH.""NetAmount"", PT.""PayTypeName"" as ""PaidVia"", LBH.""CreatedBy"", LBH.""CreatedDate"", LBH.""BookingDate"",
                            A.""FullName"" as ""CreatedByName"",(Select count(*) from ""LabBookingDetail"" where ""LabBookingHeaderId"" = LBH.""LabBookingHeaderId"")  ""NoOfTest"",
                             (CASE WHEN pa.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', pa.""Guid"", '/', pa.""ThumbnailUrl"") ELSE '' END) AS ""ThumbnailUrl""
	                            ,L.""Name"" as ""LocationName""

                                FROM ""LabBookingHeader"" LBH
                                left join ""Admission"" ad on ad.""AdmissionId"" = LBH.""AdmissionId""
                                left join ""Appointment"" ap on ap.""AppointmentId"" = LBH.""AppointmentId""
                                join ""Account"" A on A.""AccountId"" = LBH.""CreatedBy"" 

                                join ""Patient"" pa on LBH.""PatientId"" = pa.""PatientId"" 
                                Left join ""PayType"" PT on PT.""PayTypeId""=LBH.""PayTypeId""
                                    join ""Location"" L on L.""LocationId""=LBH.""LocationId""
                               {where}
	                            order by LBH.""CreatedDate"" desc";
            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

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

        /// <inheritdoc/>
        public async Task<IEnumerable<LabBookingDetailModel>> FetchBookingLabDetails(string? id, string? status, LabBookingDetailModel model)
        {
            var where = "where 1=1";
            if (model.FromDate != null)
            {
                where += $@" AND (LBH.""SampleDate"" at time zone 'UTC' at time zone 'Asia/Kolkata')::DATE >= '{model.FromDate}'::DATE";
            }

            if (model.ToDate != null)
            {
                where += $@" AND (LBH.""SampleDate"" at time zone 'UTC' at time zone 'Asia/Kolkata')::DATE <= '{model.ToDate}'::DATE";
            }
            if (id != null)
            {
                where += $@" and LBH.""LabBookingHeaderId""  = {int.Parse(id)}";
            }

            if (!string.IsNullOrEmpty(status))
            {
                where += $@" and LBH.""Status"" ilike '%{status}%' ";
            }
            if (model.AccountId != null)
            {
                where += $@" and LB.""CreatedBy"" = '{model.AccountId}'";
            }
            if (model.ProviderId != null)
            {
                where += $@" and Doctor.""ProviderId"" =  '{model.ProviderId}'";
            }
            if (model.LabDepartmentId != null)
            {
                where += $@" and LH.""LabDepartmentId"" =  '{model.LabDepartmentId}'";
            }
            if (model.LabId != null)
            {
                where += $@" and LBH.""LabHeaderId"" =  '{model.LabId}'";
            }
            var queryBooking = $@"SELECT LBH.""LabBookingDetailId"", LB.""CreatedBy"", LBH.""SampleDate"", LBH.""Barcode"",LBH.""BarcodeGeneratedBy"",BR.""FullName"" as ""BarcodeGeneratedName"",LBH.""BarcodeGeneratedDate"",LH.""LabDepartmentId"", LB.""PatientId"" ,LB.""PatientName"", LB.""DoctorName"", LBH.""LabBookingHeaderId"", LH.""LabName"",LBH.""LabHeaderId"", LBH.""Status"",
	                                LBH.""DiscountPercentage"",LBH.""DiscountAmount"",LBH.""Amount"",LBH.""NetAmount"",LBH.""IsReportGenerated"",LBH.""ReportDate""
                                        ,LBH.""Barcode"",LBH.""SampleDate"",LBH.""IsSampleCollected"",AC.""FullName"" as ""SampleCollectedBy"",LD.""DepartmentName"",LH.""LabCode""
                                        ,AR.""FullName"" as ""CollectedSampleReceivedBy"", LBH.""SampleReceivedDate"",
										Verified.""FullName"" as ""VerifiedByName"", Doctor.""FullName"" as ""VerifiedByDoctorName""  
                                    FROM ""LabBookingDetail"" LBH
                                    join ""LabBookingHeader"" LB ON LB.""LabBookingHeaderId""=LBH.""LabBookingHeaderId""
                                    join ""LabHeader"" LH on LH.""LabHeaderId"" = LBH.""LabHeaderId""
                                    join ""LabDepartment"" LD on LH.""LabDepartmentId""=LD.""LabDepartmentId""
                                    left join ""LabServices"" ls on ls.""LabServicesId"" = LBH.""LabServicesId""
                                    left join ""Account"" AC on AC.""AccountId""=LBH.""SampleCollectedBy""
                                    left join ""Account"" AR on AR.""AccountId""=LBH.""CollectedSampleReceivedBy""
									left join ""Account"" BR on BR.""AccountId""=LBH.""BarcodeGeneratedBy""
                                    left join ""Account"" Verified on Verified.""AccountId"" = LBH.""VerifiedBy""
									left join ""Provider"" Doctor on Doctor.""ProviderId"" = LBH.""VerifiedByDoctorId""
                                    left join  ""Account"" A on A.""AccountId"" = LB.""CreatedBy"" 
                                    {where} and ls.""Active"" is not false";
            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                queryBooking += $@" limit {model.PageSize} offset {model.PageIndex * model.PageSize}";
            }
            return await this.unitOfWork.Current.QueryAsync<LabBookingDetailModel>(queryBooking);

        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabBookingDetailModel>> FetchBookingLabDetailsWithPackageDataAsync(int id, LabBookingHeaderModel labBookingHeader)
        {
            var condition = $@" and 1=1";
            if (labBookingHeader != null)
            {
                var fromLabServices = labBookingHeader.AdmissionId != null || labBookingHeader.AppointmentId != null;
                if (fromLabServices)
                {
                    condition = $@" and ls.""Active"" is not false";
                }
            }

            var queryBooking = $@"SELECT LBH.""LabBookingDetailId"", LBH.""LabBookingHeaderId"",
                                    LP.""Name"" as ""LabName"",LH.""LabName"",LBH.""LabHeaderId"",LBH.""LabPackageId"", LBH.""Status"",
	                                LBH.""DiscountPercentage"",LBH.""DiscountAmount"",LBH.""Amount"",LBH.""NetAmount"",LBH.""IsReportGenerated"",LBH.""ReportDate"",LBH.""SampleDate""

                                    FROM ""LabBookingDetail"" LBH
									left join ""LabHeader"" LH on LH.""LabHeaderId"" = LBH.""LabHeaderId""
									left join ""LabPackage"" LP on LP.""LabPackageId"" = LBH.""LabPackageId""
                                    left join ""LabServices"" ls on ls.""LabServicesId"" = LBH.""LabServicesId""
                                    where LBH.""LabBookingHeaderId"" =  {id} {condition}";
            return await this.unitOfWork.Current.QueryAsync<LabBookingDetailModel>(queryBooking);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateBookingLabDetailStatus(int id, string status, int loginId)
        {
            var query = $@"UPDATE ""LabBookingDetail"" SET ""Status""='{status}',""IsSampleCollected""= true,""SampleCollectedBy""={loginId}, ""SampleDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" = {id}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateBookingLabDetailStatusAll(int id, string status, int loginId)
        {
            var query = $@"UPDATE ""LabBookingDetail"" SET ""Status""='{status}',""IsSampleCollected""= true,""SampleCollectedBy""={loginId} , ""SampleDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingHeaderId"" = {id} and ""LabPackageId"" is null";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> InsertBulkPatientParameterAsync(List<LabPatientParameterModel> model)
        {
            using (var transaction = this.unitOfWork.BeginTransaction())
            {
                var parameters = (model.Select(m => new LabPatientParameter
                {
                    LabPatientParameterId = m.LabPatientParameterId,
                    LabDetailId = m.LabDetailId,
                    TestParamResult = m.TestParamResult,
                    LabBookingDetailId = m.LabBookingDetailId,
                    LabBookingPackageDetailId = m.LabBookingPackageDetailId
                })).ToList();

                if (parameters[0].LabPatientParameterId > 0)
                {
                    var response = await this.unitOfWork.LabPatientParameters.BulkUpdateAsync(parameters, transaction);
                    if (!response)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
                else
                {
                    var response = await this.unitOfWork.LabPatientParameters.BulkInsertAsync(parameters, transaction);
                    if (response <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
                var detailResponse = 0;

                if (parameters[0].LabBookingPackageDetailId == null)
                {
                    var bookingDetail = await this.unitOfWork.LabBookingDetails.FindAsync(m => m.LabBookingDetailId == parameters[0].LabBookingDetailId);
                    if (bookingDetail == null)
                    {
                        transaction.Rollback();
                        return -2;
                    }

                    bookingDetail.ReportDate = null;
                    bookingDetail.IsReportGenerated = null;
                    bookingDetail.VerifiedBy = null;
                    bookingDetail.TypedBy = model[0].TypedBy;
                    bookingDetail.TypedDate = DateTime.UtcNow.AddMinutes(330);
                    bookingDetail.Status = "Report generated but not verified.";

                    detailResponse = await this.unitOfWork.LabBookingDetails.UpdateAsync(bookingDetail, transaction);
                    if (detailResponse <= 0)
                    {
                        transaction.Rollback();
                        return -3;
                    }
                }
                else
                {
                    var labBookingPackageDetail = await this.unitOfWork.LabBookingPackageDetails.FindAsync(m => m.LabBookingPackageDetailId == parameters[0].LabBookingPackageDetailId);
                    if (labBookingPackageDetail == null)
                    {
                        transaction.Rollback();
                        return -4;
                    }
                    labBookingPackageDetail.ReportDate = null;
                    labBookingPackageDetail.IsReportGenerated = null;
                    labBookingPackageDetail.VerifiedBy = null;
                    labBookingPackageDetail.TypedBy = model[0].TypedBy;
                    labBookingPackageDetail.TypedDate = DateTime.UtcNow.AddMinutes(330);
                    labBookingPackageDetail.Status = "Report generated but not verified.";

                    detailResponse = await this.unitOfWork.LabBookingPackageDetails.UpdateAsync(labBookingPackageDetail, transaction);
                    if (detailResponse <= 0)
                    {
                        transaction.Rollback();
                        return -3;
                    }

                    try
                    {
                        await this.CheckLabBookingPackageVerifiedAndReportStatus(parameters[0].LabBookingDetailId, model[0].TypedBy, "typedCheck", transaction);
                    }
                    catch (Exception)
                    {
                        // ignore.
                    }
                }
                transaction.Commit();
                return detailResponse;
            }
        }

        /// <inheritdoc/>
        public async Task<LabReportMainModel> FetchLabReportMainDataAsync(int labBookingDetailId)
        {
            var query = $@"Select LBD.""LabBookingDetailId"",  LBD.""LabBookingHeaderId"",  LBD.""LabHeaderId"",  LBD.""Amount"",  LBD.""Status"",
                                 LBD.""IsReportGenerated"",  LBD.""ReportDate"",LH.""LabCode"", LH.""Signature"",LH.""LabName"" ,
                                 LBH.""PatientType"", LBH.""BillNumber"", LBH.""PatientId"", P.""FullName"" as ""PatientName"", P.""Mobile"", LBH.""DoctorName"", LBH.""NetAmount"", 
                                 LBH.""PaidVia"", LBH.""CreatedBy"", LBH.""CreatedDate"",A.""FullName"" as ""CreatedByName"",
								 P.""UMRNo"",P.""Age"",P.""Gender"",LBD.""IsSampleCollected"",LBD.""SampleDate""
                                 from ""LabBookingDetail"" LBD
                                 join ""LabHeader"" LH on LH.""LabHeaderId"" = LBD.""LabHeaderId""
                                 join ""LabBookingHeader"" LBH on LBH.""LabBookingHeaderId"" = LBD.""LabBookingHeaderId""
								 left join ""Patient"" P on P.""PatientId"" = LBH.""PatientId""
                                 join ""Account"" A on A.""AccountId"" = LBH.""CreatedBy""
                                 where LBD.""LabBookingDetailId"" = {labBookingDetailId}";
            return await this.unitOfWork.Current.QuerySingleAsync<LabReportMainModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabReportParamModel>> FetchLabResultReportParameterAsync(int labBookingDetailId)
        {
            var query = $@"SELECT distinct LD.""LabDetailId"", LD.""LabHeaderId"", LD.""TestParameter"", LD.""ReferenceRange"", LD.""RefrenceRangeUnit"",
                                LV.""Name"" as ""RefrenceRangeUnitName"",LPP.""LabPatientParameterId"", LPP.""LabDetailId"", LPP.""TestParamResult"",
                                LBD.""TypedBy"", LBD.""TypedDate"", A.""FullName"" as ""TypedByName"", LBD.""VerifiedBy"",
								V.""FullName"" as ""VerifiedByName"", Doctor.""FullName"" as ""VerifiedByDoctorName""
	                                FROM ""LabDetail"" LD
	                                left join ""LookupValue"" LV on LV.""LookupValueId"" = LD.""RefrenceRangeUnit""
	                                join ""LabPatientParameter"" LPP on LPP.""LabDetailId"" = LD.""LabDetailId""
	                                join ""LabBookingDetail"" LBD on LBD.""LabBookingDetailId"" = LPP.""LabBookingDetailId""
									join ""Account"" A on A.""AccountId"" = LBD.""TypedBy""
									left join ""Account"" V on V.""AccountId"" = LBD.""VerifiedBy""
									left join ""Provider"" Doctor on Doctor.""ProviderId"" = LBD.""VerifiedByDoctorId""
	                                where LPP.""LabBookingDetailId"" = {labBookingDetailId} and ""LabBookingPackageDetailId"" is null";
            return await this.unitOfWork.Current.QueryAsync<LabReportParamModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabDailyReportModel>> FetchLabDailyReport(RequestLaboratory model)
        {
            var where = $@"where 1=1 and LBH.""Active"" is true ";
            if (model.RequestDate != null)
            {
                where += $@" and LBH.""CreatedDate""::date = '{model.RequestDate?.ToString("yyyy-MM-dd")}'";
            }
            if (model.LocationId > 0)
            {
                where += $@" and  LBH.""LocationId"" ={model.LocationId} ";
            }
            //if (model.FromDate != null)
            //{
            //    where += $@" and LBH.""CreatedDate""::date >= '{model.FromDate}' ";
            //}

            //if (model.ToDate != null)
            //{
            //    where += $@" and LBH.""CreatedDate""::date  <= '{model.ToDate}' ";
            //}
            if (model.FromDate != null)
            {
                where += $@" and LBH.""CreatedDate""::date >= '{model.FromDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.ToDate != null)
            {
                where += $@" and LBH.""CreatedDate""::date  <= '{model.ToDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.SelectedFromDate != null)
            {
                where += $@" and LBH.""CreatedDate""::date >= '{model.SelectedFromDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.SelectedToDate != null)
            {
                where += $@" and LBH.""CreatedDate""::date  <= '{model.SelectedToDate?.ToString("yyyy-MM-dd")}' ";
            }

            if (model.UMRNo != null)
            {
                where += $@" and P.""UMRNo"" ilike '%{model.UMRNo}%'";

            }
            if (model.Mobile != null)
            {
                where += $@" and P.""Mobile"" ilike '%{model.Mobile}%'";

            }
            if (model.ProviderId != null)
            {
                where += $@" and LBH.""ProviderId"" = {model.ProviderId}";
            }
            if (model.BillNumber != null)
            {
                where += $@" and LBH.""BillNumber"" ilike '%{model.BillNumber}%'";
            }
            if (model.AccountId != null)
            {
                where += $@" and LBH.""CreatedBy"" = {model.AccountId}";
            }
            if (model.PatientId != null)
            {
                where += $@" and LBH.""PatientId"" = {model.PatientId}";
            }
            //if (model.PaidVia != null)
            //{
            //    where += $@" and lower(LBH.""PaidVia"") = lower('{model.PaidVia}')";
            //}
            if (model.PayTypeId != null)
            {
                where += $@" and LBH.""PayTypeId""= {model.PayTypeId}";
            }
            //if (model.DoctorName != null)
            //{
            //    where += $@" and LBH.""DoctorName"" = '{model.DoctorName}'";
            //}
            if (model.LabName != null)
            {
                where += $@" and LH.""LabName""ilike '%{model.LabName}%'";
            }
            //if (model.LabPackageId != null)
            //{
            //    where += $@" and LP.""LabPackageId"" = '{model.LabPackageId}'";

            //}
            if (model.PackageId != null)
            {
                if (model.PackageId == "true")
                {
                    where += $@" AND LP.""LabPackageId"" is not null";
                }
                else
                {
                    where += $@" AND LP.""LabPackageId"" is null";
                }
            }
            var query = $@"SELECT LH.""LabName"",LP.""Name"" as ""LabName"",LP.""LabPackageId"",P.""FullName"" as ""PatientName"",P.""UMRNo"",P.""Mobile"",PT.""PayTypeName"",LBH.""PaymentNumber"" ,LBD.""Amount"",LBH.""DoctorName"", D.""DepartmentName"" ,
                                    LBH.""LabBookingHeaderId"", LBH.""BillNumber"", LBH.""PatientId"",  LBH.""CreatedBy"", LBH.""CreatedDate"",
									LBH.""BookingDate"",
                                    P.""Age"",p.""Gender"", 
                                    LBD.""DiscountPercentage"",LBD.""DiscountAmount"",LBD.""NetAmount"",
									A.""FullName"" as ""CreatedByName"",sum(LBD.""Amount"") over() as ""GrandTotal""
									,sum(LBD.""NetAmount"") over() as ""OverallNetAmount"",
									sum(LBD.""DiscountAmount"") over() as ""OverallDiscountAmount""
	                                                FROM ""LabBookingHeader"" LBH
				                                  left  join ""LabBookingDetail"" LBD on LBD.""LabBookingHeaderId"" = LBH.""LabBookingHeaderId""
				                                    left join ""LabHeader"" LH on LH.""LabHeaderId"" = LBD.""LabHeaderId""
													left join ""LabPackage"" LP on LP.""LabPackageId"" = LBD.""LabPackageId""
				                                    join ""Patient"" P on P.""PatientId"" = LBH.""PatientId""
	                                                join ""Account"" A on A.""AccountId"" = LBH.""CreatedBy"" 
                                                    join ""Provider"" DP on DP.""ProviderId"" = LBH.""ProviderId"" 
                                                    join ""Department"" D on D.""DepartmentId"" = DP.""DepartmentId""
                                                   left join ""PayType"" PT on PT.""PayTypeId""=LBH.""PayTypeId""
                                                    {where}
	                                                order by LBH.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<LabDailyReportModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LabsDashboardRevenueModel>> FetchLabRevenueGraphReport()
        {
            var query = $@"select  distinct A.""LabName""::text,round(A.""LabTotal"" / A.""GrandTotal"" * 100, 2)::text ""LabTotalPercentage"" from ( 
                SELECT LH.""LabName"",LBD.""Amount"",LBD.""NetAmount"",sum(LBD.""Amount"") over(partition by LBH.""LabBookingHeaderId"") as""LabTotal"",
                sum(LBD.""Amount"") over() as""GrandTotal"",
                LBH.""LabBookingHeaderId"",
	            sum(LBD.""NetAmount"") over() as""OverallNetAmount"",
                sum(LBD.""DiscountAmount"") over() as""OverallDiscountAmount""
                FROM""LabBookingHeader"" LBH
                join""LabBookingDetail"" LBD on LBD.""LabBookingHeaderId"" = LBH.""LabBookingHeaderId""
                join""LabHeader"" LH on LH.""LabHeaderId"" = LBD.""LabHeaderId""
                join""Patient"" P on P.""PatientId"" = LBH.""PatientId""
                join""Account"" A on A.""AccountId"" = LBH.""CreatedBy"" 
                where 1 = 1
                order by LBH.""LabBookingHeaderId"" desc) a";
            return await this.unitOfWork.Current.QueryAsync<LabsDashboardRevenueModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> VerifyLabReportAsync(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 Verified By Technician";(on vikas requirement)
            bookingDetail.Status = "Report Generated";
            bookingDetail.VerifiedBy = verifiedBy;
            return await this.unitOfWork.LabBookingDetails.UpdateAsync(bookingDetail);
        }

        /// <inheritdoc/>
        public async Task<int> CancelLabBookingAsync(int bookingHeaderId, int modifiedBy)
        {
            var bookingHeaderDetail = await this.unitOfWork.LabBookingHeaders.FindAsync(m => m.LabBookingHeaderId == bookingHeaderId);
            if (bookingHeaderDetail == null)
            {
                return -1;
            }

            bookingHeaderDetail.Active = false;
            bookingHeaderDetail.ModifiedBy = modifiedBy;
            bookingHeaderDetail.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            var response = await this.unitOfWork.LabBookingHeaders.UpdateAsync(bookingHeaderDetail);

            var allBookingDetails = await this.unitOfWork.LabBookingDetails.FindAllAsync(m => m.LabBookingHeaderId == bookingHeaderId);

            foreach (var item in allBookingDetails)
            {
                if (item.LabServicesId != null)
                {
                    var labService = await this.unitOfWork.LabServices.FindAsync(m => m.LabServicesId == item.LabServicesId);
                    labService.Active = false;
                    labService.ModifiedBy = modifiedBy;
                    labService.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
                    await this.unitOfWork.LabServices.UpdateAsync(labService);
                }
            }

            return response;
            //var bookingDetails = (await this.unitOfWork.LabBookingDetails.FindAllAsync(m => m.LabBookingHeaderId == bookingHeaderDetail.LabBookingHeaderId)).ToList();
            //if (bookingDetails.Count == 0)
            //{
            //    return -2;
            //}

            //var checkPackageBooking = bookingDetails.Where(m => m.LabPackageId != null).ToList();
            //using (var transaction = this.unitOfWork.BeginTransaction())
            //{
            //    if (checkPackageBooking.Count > 0)
            //    {
            //        var bookingIds = string.Join(",", checkPackageBooking.Select(m => m.LabBookingDetailId));
            //        var query = $@"DELETE FROM ""LabBookingPackageDetail"" WHERE ""LabBookingDetailId"" in ({bookingIds})";
            //        var packageDeleteResponse = await this.unitOfWork.Current.ExecuteAsync(query, transaction);
            //        if (packageDeleteResponse <= 0)
            //        {
            //            transaction.Rollback();
            //            return -3;
            //        }
            //    }
            //    var bookinDetailQuery = $@"DELETE FROM ""LabBookingDetail""	WHERE ""LabBookingHeaderId"" = {bookingHeaderDetail.LabBookingHeaderId}";

            //    var bookingDetailResponse = await this.unitOfWork.Current.ExecuteAsync(bookinDetailQuery, transaction);
            //    if (bookingDetailResponse <= 0)
            //    {
            //        transaction.Rollback();
            //        return -4;
            //    }

            //    var bookinHeaderQuery = $@"DELETE FROM ""LabBookingHeader""	WHERE ""LabBookingHeaderId"" = {bookingHeaderDetail.LabBookingHeaderId}";

            //    var bookingHeaderResponse = await this.unitOfWork.Current.ExecuteAsync(bookinHeaderQuery, transaction);
            //    if (bookingHeaderResponse <= 0)
            //    {
            //        transaction.Rollback();
            //        return -5;
            //    }
            //    transaction.Commit();
            //    return bookingHeaderResponse;
            //}
        }

        /// <inheritdoc/>
        public async Task<LabHeaderModel> FetchLab(int labBookingPackageDetailId)
        {
            var query = $@"select LH.""LabName"" from ""LabBookingPackageDetail"" LBP
                            JOIN ""LabHeader"" LH on LH.""LabHeaderId"" = LBP.""LabHeaderId""
                            where  LBP.""LabBookingPackageDetailId"" = {labBookingPackageDetailId}";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<LabHeaderModel>(query);
        }

        /// <inheritdoc/>
        public async Task<Tuple<LabBookingHeaderModel, int>> CancelSingleLabFromBooking(int labBookingHeaderId, int labBookingDetailId)
        {
            var header = await this.unitOfWork.LabBookingHeaders.FindAsync(m => m.LabBookingHeaderId == labBookingHeaderId);
            if (header == null)
            {
                return Tuple.Create(new LabBookingHeaderModel(), 0);
            }

            var bookingHeader = new LabBookingHeaderModel
            {
                BillNumber = header.BillNumber
            };

            var labToBeCancelled = await this.unitOfWork.LabBookingDetails.FindAsync(c => c.LabBookingHeaderId == header.LabBookingHeaderId && c.LabBookingDetailId == labBookingDetailId);

            if (labToBeCancelled == null)
            {
                return Tuple.Create(new LabBookingHeaderModel(), 0);
            }

            if (labToBeCancelled.LabPackageId != null)
            {
                var labsInPackageBooking = await this.unitOfWork.LabBookingPackageDetails.FindAllAsync(p => p.LabBookingDetailId == labToBeCancelled.LabBookingDetailId);

                foreach (var package in labsInPackageBooking)
                {
                    var deletePackageResponse = await this.unitOfWork.LabBookingPackageDetails.DeleteAsync(package);
                    if (!deletePackageResponse)
                    {
                        return Tuple.Create(new LabBookingHeaderModel(), -1);
                    }
                }
            }

            header.TotalAmount -= labToBeCancelled.Amount;
            header.NetAmount -= labToBeCancelled.NetAmount;

            var deleteResponse = await this.unitOfWork.LabBookingDetails.DeleteAsync(labToBeCancelled);
            if (!deleteResponse)
            {
                return Tuple.Create(new LabBookingHeaderModel(), -1);
            }

            var headerUpdateResponse = await this.unitOfWork.LabBookingHeaders.UpdateAsync(header);

            if (headerUpdateResponse == 0)
            {
                return Tuple.Create(new LabBookingHeaderModel(), -1);
            }

            return Tuple.Create(bookingHeader, 1);
        }


        /// <summary>
        /// The check lookup value name.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="lookupId">
        /// The lookup id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<bool> CheckLookupValueName(string name, int lookupId)
        {
            var lookup = await this.unitOfWork.LookupValues.FindAllAsync(m => m.LookupId == lookupId);
            var match = lookup?.ToList().Find(
                m => string.Equals(m.Name, name, StringComparison.CurrentCultureIgnoreCase));
            return match != null;
        }

        /// <summary>
        /// The get bill number.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<string> GetBillNumber()
        {
            var billQuery = $@"SELECT ""BillNumber"" FROM ""LabBookingHeader""
                                        ORDER BY ""LabBookingHeaderId"" DESC LIMIT 1";
            var oldBillNumber = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(billQuery);
            if (string.IsNullOrEmpty(oldBillNumber))
            {
                // LAAB2021040101
                return "LA" + CoreFilter.Random(2) + DateTime.Now.ToString("yyyyMMdd") + "1";
            }
            else
            {
                var stringLiterals = oldBillNumber.Substring(0, 4);
                var previousBillDateWithCount = oldBillNumber.Substring(4);
                var counter = previousBillDateWithCount.Substring(8);
                var date = previousBillDateWithCount.Substring(0, 8);
                if (date != DateTime.Now.ToString("yyyyMMdd"))
                {
                    return "LA" + CoreFilter.Random(2) + DateTime.Now.ToString("yyyyMMdd") + "1";
                }

                counter = (int.Parse(counter) + 1).ToString();
                return stringLiterals + date + counter;
            }
        }

        /// <summary>
        /// The check lab booking package verified and report status.
        /// </summary>
        /// <param name="labBookingId">
        /// The lab booking id.
        /// </param>
        /// <param name="typedBy">
        /// The typed by.
        /// </param>
        /// <param name="cases">
        /// The cases.
        /// </param>
        /// <param name="transaction">
        /// The transaction.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>
        /// </returns>
        private async Task<bool> CheckLabBookingPackageVerifiedAndReportStatus(int labBookingId, int? typedBy, string cases, System.Data.IDbTransaction transaction)
        {
            var fetchAllPackageLabs = (await this.unitOfWork.LabBookingPackageDetails.FindAllAsync(m => m.LabBookingDetailId == labBookingId)).ToList();
            var bookingDetail = await this.unitOfWork.LabBookingDetails.FindAsync(m => m.LabBookingDetailId == labBookingId);
            if (fetchAllPackageLabs.Count > 0 && cases == "typedCheck")
            {
                var isAnyRecordMissing = (fetchAllPackageLabs.Where(m => m.TypedBy == null)).ToList();
                if (isAnyRecordMissing.Count > 0)
                {
                    return false;
                }
                else
                {
                    bookingDetail.ReportDate = null;
                    bookingDetail.IsReportGenerated = null;
                    bookingDetail.VerifiedBy = null;
                    bookingDetail.TypedBy = typedBy;
                    bookingDetail.TypedDate = DateTime.UtcNow.AddMinutes(330);
                    bookingDetail.Status = "Report generated but not verified.";

                    return await this.unitOfWork.LabBookingDetails.UpdateAsync(bookingDetail, transaction) > 0;
                }
            }

            return false;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LocationLabHeaderMapModel>> FetchLabLocationCharges(int locationId, int labHeaderId)
        {
            var where = $@"where 1=1";
            /* if (locationId != null)
             {
                 where += $@" and LHM.""LocationId"" = {locationId}";
             }*/
            if (labHeaderId > 0)
            {
                where += $@" and LHM.""LabHeaderId"" = {labHeaderId}";
            }
            var query = $@"select L.""Name"" as ""LocationName"",LHM.""Charge"" as ""TestCharge"",LHM.* from ""LocationLabHeaderMap"" LHM 
                            join ""Location"" L on L.""LocationId"" = LHM.""LocationId"" 
                            {where}";
            return await this.unitOfWork.Current.QueryAsync<LocationLabHeaderMapModel>(query);
        }
        /// <inheritdoc/>
        public async Task<int> UpdateLabBookingDetailForBarcodeAsync(LabSample model)
        {
            var response = 0;
            var flagcheck = false;
            if (model.LabBookingDetailIds.Any())
            {
                var ids = string.Join(",", model.LabBookingDetailIds);
                var query = $@"UPDATE ""LabBookingDetail""  SET ""Barcode""=true,""BarcodeGeneratedBy""={model.BarcodeGeneratedBy}, ""BarcodeGeneratedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" in  ({ids})";
                response = await this.unitOfWork.Current.ExecuteAsync(query);
            }

            if (model.labBookingPackageDetailIds.Any())
            {
                flagcheck = true;
                var ids = string.Join(",", model.labBookingPackageDetailIds);
                var query = $@"UPDATE ""LabBookingPackageDetail""  SET ""Barcode""=true,""BarcodeGeneratedBy""={model.BarcodeGeneratedBy}, ""BarcodeGeneratedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingPackageDetailId"" in  ({ids})";
                response = await this.unitOfWork.Current.ExecuteAsync(query);
            }
            try
            {
                for (int i = 0; i < model.labBookingPackageDetailIds.Count; i++)
                {
                    if (response > 0 && flagcheck)
                    {
                        var getAnPackageBooking = await this.unitOfWork.LabBookingPackageDetails.FindAsync(x => x.LabBookingPackageDetailId == model.labBookingPackageDetailIds[i]);
                        if (getAnPackageBooking != null)
                        {

                            var getAllTheLabsInPackage = (await this.unitOfWork.LabBookingPackageDetails.FindAllAsync(x => x.LabBookingDetailId == getAnPackageBooking.LabBookingDetailId)).ToList();
                            if (getAllTheLabsInPackage.Count > 0)
                            {
                                var checktoupdate = (getAllTheLabsInPackage.Where(c => c.SampleCollectedBy == (int?)null)).ToList();
                                if (checktoupdate.Count == 0)
                                {
                                    var query = $@"UPDATE ""LabBookingDetail""  SET ""Barcode""=true,""BarcodeGeneratedBy""={model.BarcodeGeneratedBy}, ""BarcodeGeneratedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" = {getAnPackageBooking.LabBookingDetailId}";
                                    response = await this.unitOfWork.Current.ExecuteAsync(query);
                                }
                            }
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                // ignore
            }
            return response;
        }
        /// <inheritdoc/>
        //public async Task<int> UpdateSampleReceivedStatus(int labBookingDetailId, int loginId)
        //{
        //    var query = $@"UPDATE ""LabBookingDetail"" SET ""CollectedSampleReceivedBy""={loginId}, ""SampleReceivedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" = {labBookingDetailId}";
        //    return await this.unitOfWork.Current.ExecuteAsync(query);
        //}     

        /// <inheritdoc/>
        public async Task<int> UpdateSelectedLabReceived(LabSample model)
        {
            try
            {
                var response = 0;
                var checkIf = false;
                if (model.LabBookingDetailIds.Any())
                {
                    var ids = string.Join(",", model.LabBookingDetailIds);
                    var query = $@"UPDATE ""LabBookingDetail""  SET ""Status""='Sample Received', ""CollectedSampleReceivedBy""={model.AccountId}, ""SampleReceivedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" in  ({ids})";
                    response = await this.unitOfWork.Current.ExecuteAsync(query);
                }
                if (model.labBookingPackageDetailIds.Any())
                {
                    var ids = string.Join(",", model.labBookingPackageDetailIds);
                    checkIf = true;
                    var query = $@"UPDATE ""LabBookingPackageDetail""  SET ""Status""='Sample Received', ""CollectedSampleReceivedBy""={model.AccountId}, ""SampleReceivedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingPackageDetailId"" in  ({ids})";
                    response = await this.unitOfWork.Current.ExecuteAsync(query);
                }
                for (int i = 0; i < model.labBookingPackageDetailIds.Count; i++)
                {
                    if (response > 0 && checkIf)
                    {
                        var getAnPackageBooking = await this.unitOfWork.LabBookingPackageDetails.FindAsync(x => x.LabBookingPackageDetailId == model.labBookingPackageDetailIds[i]);
                        if (getAnPackageBooking != null)
                        {
                            var getAllTheLabsInPackage = (await this.unitOfWork.LabBookingPackageDetails.FindAllAsync(x => x.LabBookingDetailId == getAnPackageBooking.LabBookingDetailId)).ToList();
                            if (getAllTheLabsInPackage.Count > 0)
                            {
                                var checkUnReceived = (getAllTheLabsInPackage.Where(c => c.CollectedSampleReceivedBy == (int?)null)).ToList();
                                if (checkUnReceived.Count == 0)
                                {
                                    var query = $@"UPDATE ""LabBookingDetail""  SET ""Status""='Sample Received', ""CollectedSampleReceivedBy""={model.AccountId}, ""SampleReceivedDate"" = '{DateTime.UtcNow.AddMinutes(330).ToString("yyyy-MM-dd hh:mm tt")}' WHERE ""LabBookingDetailId"" = {getAnPackageBooking.LabBookingDetailId}";
                                    response = await this.unitOfWork.Current.ExecuteAsync(query);
                                }
                            }
                        }
                    }
                }
                return response;
            }
            catch (Exception ex)
            {
                throw;
            }
        }

        /// <inheritdoc />
        public Task<IEnumerable<PatientModel>> FetchExistingPatientsAsync(PatientModel model)
        {
            var parameters = !string.IsNullOrEmpty(model.Filter) ? $@"'{model.Filter}'" : "null";
            parameters += !string.IsNullOrEmpty(model.Mobile) ? $@",'{model.Mobile}'" : ",null";
            //parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo.Trim()}'" : ",null";            
            parameters += !string.IsNullOrEmpty(model.UMRNo) ? $@",'{model.UMRNo}'" : ",null";
            parameters += !string.IsNullOrEmpty(model.FullName) ? $@",'{model.FullName.Trim()}'" : ",null";
            parameters += !string.IsNullOrEmpty(model.BillNumber) ? $@",'{model.BillNumber}'" : ",null";


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

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

        public async Task<int> ModifyImportLabAsync(LabImportModel model)
        {
            try
            {
                using (var transaction = this.unitOfWork.BeginTransaction())
                {
                    foreach (var item in model.Labs)
                    {
                        var locationHeaderMap = new LocationLabHeaderMap
                        {
                            InPatientCharge = (decimal)item.InPatientCharge,
                            Charge = (decimal)item.Charge,
                            LabHeaderId = item.LabHeaderId,
                            LocationId = model.LocationId,
                            CreatedBy = model.CreatedBy,
                            CreatedDate = DateTime.Now,
                            IsActive = true
                        };

                        var response = await this.unitOfWork.LocationLabHeaderMap.InsertAsync(locationHeaderMap, transaction);
                    }


                    //var parameters = (model.Select(m => new LocationLabHeaderMap
                    //{
                    //    InPatientCharge = (decimal)m.InPatientCharge,
                    //    Charge = (decimal)m.Charge,
                    //    LabHeaderId = m.LabHeaderId,
                    //    LocationId = m.LocationId,
                    //    CreatedBy = m.CreatedBy,
                    //    CreatedDate = DateTime.Now,
                    //    IsActive = true
                    //})).ToList();
                    //var response = this.unitOfWork.LocationLabHeaderMap.BulkInsert(parameters, transaction);
                    transaction.Commit();
                    return 1;
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }

    }
}