using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Dapper;
using Hims.Domain.Entities;
using Hims.Shared.UserModels.ProgressReport.Medication;
using Timeline = Hims.Shared.UserModels.ProgressReport.Timeline;
using MedicationInfo = Hims.Shared.UserModels.ProgressReport.MedicationInfo;
using General = Hims.Shared.UserModels.ProgressReport.General;
using Diet = Hims.Shared.UserModels.ProgressReport.Diet;

namespace Hims.Infrastructure.Services
{
    using Hims.Domain.Configurations;
    using Hims.Domain.Repositories.UnitOfWork;
    using Hims.Domain.Services;
    using System.Collections;
    using System.ComponentModel.Design;
    using System.Transactions;

    /// <summary> The chat service.</summary>
    public class ProgressReportService : IProgressReportService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// The amazon s3 configuration.
        /// </summary>
        private readonly IAmazonS3Configuration configuration;

        /// <inheritdoc cref="IChatService" />
        public ProgressReportService(IUnitOfWork unitOfWork, IAmazonS3Configuration configuration)
        {
            this.unitOfWork = unitOfWork;
            this.configuration = configuration;
        }

        public async Task<int> AddMedicationAsync(InsertModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            try
            {
                var progressReport = await this.unitOfWork.ProgressReport.FindAsync(x => x.AdmissionId == model.AdmissionId, transaction);
                var progressReportId = progressReport?.ProgressReportId ?? await this.unitOfWork.ProgressReport.InsertAsync(new ProgressReport
                {
                    AdmissionId = model.AdmissionId,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now
                }, transaction);

                foreach (var record in model.Records)
                {
                    var medication = new ProgressReportMedication
                    {
                        CreatedBy = model.CreatedBy,
                        ProgressReportId = progressReportId,
                        CreatedDate = DateTime.Now,
                        Active = true,
                        Duration = record.Duration,
                        Instructions = record.Instructions,
                        MedicationDurationTypeId = record.MedicationDurationTypeId,
                        PharmacyProductId = record.PharmacyProductId,
                        Unit = record.Unit,
                        StartDate = record.StartDate,
                        EndDate = record.EndDate
                    };

                    var medicationId = await this.unitOfWork.ProgressReportMedication.InsertAsync(medication, transaction);
                    if (medicationId <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                    if (record.MedicationInstructions.Count > 0)
                    {
                        var instructions = record.MedicationInstructions.Select(x => new ProgressReportMedicationFrequency
                        {
                            MedicationInstructionTypeId = x,
                            ProgressReportMedicationId = medicationId
                        });

                        var response = await this.unitOfWork.ProgressReportMedicationFrequency.BulkInsertAsync(instructions);
                        if (response <= 0)
                        {
                            transaction.Rollback();
                            return -1;
                        }
                    }
                    else
                    {
                        var instructions = record.TimeLineId.Select(x => new ProgressReportMedicationFrequency
                        {
                            MedicationInstructionTypeId = x,
                            ProgressReportMedicationId = medicationId
                        });

                        var response = await this.unitOfWork.ProgressReportMedicationFrequency.BulkInsertAsync(instructions);
                        if (response <= 0)
                        {
                            transaction.Rollback();
                            return -1;
                        }
                    }
                }

                transaction.Commit();
                return 1;
            }
            catch (Exception)
            {
                transaction.Rollback();
                return -1;
            }
        }

        public async Task<int> UpdateMedicationAsync(UpdateModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();
            try
            {
                var progressReport = await this.unitOfWork.ProgressReport.FindAsync(x => x.AdmissionId == model.AdmissionId, transaction);
                var medicationReport = await this.unitOfWork.ProgressReportMedication.FindAsync(m => m.ProgressReportMedicationId == model.ProgressReportMedicationId, transaction);
                if (model.ProgressReportMedicationId > 0)
                {
                    medicationReport.ModifiedBy = model.ModifiedBy;
                    medicationReport.ModifiedDate = DateTime.Now;
                    medicationReport.Duration = model.Duration;
                    medicationReport.Instructions = model.Instructions;
                    medicationReport.Unit = model.Unit;
                };

                var medicationId = await this.unitOfWork.ProgressReportMedication.UpdateAsync(medicationReport, transaction);

                var deletequery = $@"delete from ""ProgressReportMedicationFrequency""  where ""ProgressReportMedicationId""= {model.ProgressReportMedicationId}";

                var deleteResponse = await this.unitOfWork.Current.ExecuteAsync(deletequery, transaction);

                if (model.NightInstructionTypeId > 0)
                {
                    var medication = new ProgressReportMedicationFrequency
                    {
                        ProgressReportMedicationId = model.ProgressReportMedicationId,
                        MedicationInstructionTypeId = (int)model.NightInstructionTypeId,

                    };
                    var medicationId1 = await this.unitOfWork.ProgressReportMedicationFrequency.InsertAsync(medication, transaction);
                }

                if (model.MorningInstructionTypeId > 0)
                {
                    var medication2 = new ProgressReportMedicationFrequency
                    {
                        ProgressReportMedicationId = model.ProgressReportMedicationId,
                        MedicationInstructionTypeId = (int)model.MorningInstructionTypeId,

                    };
                    var medicationId2 = await this.unitOfWork.ProgressReportMedicationFrequency.InsertAsync(medication2, transaction);
                }
                if (model.AfternoonInstructionTypeId > 0)
                {
                    var medication3 = new ProgressReportMedicationFrequency
                    {
                        ProgressReportMedicationId = model.ProgressReportMedicationId,
                        MedicationInstructionTypeId = (int)model.AfternoonInstructionTypeId,

                    };
                    var medicationId3 = await this.unitOfWork.ProgressReportMedicationFrequency.InsertAsync(medication3, transaction);
                }
                if (model.TimeLineId.Count > 0)
                {
                    var instructions = model.TimeLineId.Select(x => new ProgressReportMedicationFrequency
                    {
                        MedicationInstructionTypeId = x,
                        ProgressReportMedicationId = model.ProgressReportMedicationId,
                    });
                    var response = await this.unitOfWork.ProgressReportMedicationFrequency.BulkInsertAsync(instructions);
                }
                transaction.Commit();
                return 1;
            }
            catch (Exception ex)
            {
                transaction.Rollback();
                return -1;
            }
        }

        public async Task<int> DeleteMedicationAsync(DeleteModel model)
        {
            var medication = await this.unitOfWork.ProgressReportMedication.FindAsync(x => x.ProgressReportMedicationId == model.Id);

            var response = await this.unitOfWork.ProgressReportMedication.DeleteAsync(medication);

            var deletequery = $@"delete from ""ProgressReportMedicationFrequency""  where ""ProgressReportMedicationId""= {model.Id}";

            var deleteResponse = await this.unitOfWork.Current.ExecuteAsync(deletequery);


            //if (response == 0)
            //{
            //    return this.ServerError();
            //}
            if (medication == null)
            {
                return -1;
            }

            //medication.Active = false;
            //medication.StopReason = model.StopReason;
            //medication.StopDate = DateTime.Now;
            //medication.ModifiedBy = model.By;
            //medication.ModifiedDate = DateTime.Now;

            //var response = await this.unitOfWork.ProgressReportMedication.UpdateAsync(medication);
            return 1;
        }
        public async Task<int> StopMedicationAsync(StopModel model)
        {
            var medication = await this.unitOfWork.ProgressReportMedication.FindAsync(x => x.ProgressReportMedicationId == model.Id);
            if (medication == null)
            {
                return -1;
            }

            medication.Active = false;
            medication.StopReason = model.StopReason;
            medication.StopDate = DateTime.Now;
            medication.ModifiedBy = model.By;
            medication.ModifiedDate = DateTime.Now;

            var response = await this.unitOfWork.ProgressReportMedication.UpdateAsync(medication);
            return response;
        }

        public async Task<int> TakeMedicationAsync(List<TakeModel> model)
        {
            var list = new List<ProgressReportMedicationDaily>();
            foreach (var item in model)
            {
                var medicationDate = item.MedicationDate != null
                    ? new DateTime(item.MedicationDate.Year, item.MedicationDate.Month, item.MedicationDate.Day, 0, 0, 0)
                    : DateTime.Today;

                foreach (var id in item.InstructionIds)
                {
                    var query = $@"SELECT COUNT(*) FROM ""ProgressReportMedicationDaily"" WHERE ""ProgressReportMedicationFrequencyId"" = {id} AND to_char(""MedicationDate"", 'YYYY-MM-DD') = '{medicationDate:yyyy-MM-dd}' ";
                    var count = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int?>(query);
                    if (count == null || count == 0)
                    {
                        list.Add(new ProgressReportMedicationDaily
                        {
                            CreatedBy = item.By,
                            CreatedDate = DateTime.Now,
                            ProgressReportMedicationFrequencyId = id,
                            MedicationDate = medicationDate,
                            Status = true
                        });
                    }
                }
            }


            if (!list.Any()) return 1;


            var response = await this.unitOfWork.ProgressReportMedicationDaily.BulkInsertAsync(list);
            return response;
        }

        public async Task<IEnumerable<InstructionViewModel>> FetchInstructionsAsync()
        {
            var query = $@"SELECT
	                                ""MedicationInstructionTypeId"" ""Id"",
	                                ""Type"",
	                                ""Name"" 
                                FROM
	                                ""MedicationInstructionType""";
            var records = await this.unitOfWork.Current.QueryAsync<InstructionViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<MasterViewModel>> FetchMasterMedicationsAsync(string term)
        {
            var query = $@"SELECT
                                    p.""PharmacyProductId"" ""Id"",
                                    p.""ProductName"" ""Name"",
                                    p.""GenericName"",
                                    v.""Name"" ""TypeName"",
                                    c.""Name"" ""CompanyName"",
                                    s.""Name"" ""SupplierName""
                                FROM
                                    ""PharmacyProduct"" p
                                    LEFT JOIN ""LookupValue"" v on v.""LookupValueId"" = p.""CategoryId""
                                    LEFT JOIN ""Company"" c on c.""CompanyId"" = p.""CompanyId""
                                    LEFT JOIN ""Supplier"" s on s.""SupplierId"" = p.""SupplierId""
                                WHERE p.""ProductName"" ILIKE '%{term}%' OR p.""GenericName"" ILIKE '%{term}%' OR c.""Name"" ILIKE '%{term}%' OR s.""Name"" ILIKE '%{term}%'
                                LIMIT 10";

            var records = await this.unitOfWork.Current.QueryAsync<MasterViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<Diet.MasterViewModel>> FetchMealTypeAsync(string term)
        {
            var query = $@"SELECT MT.""MealTypeId"",MT.""MealType"",A.""FullName"" as ""CreatedByName"",M.""FullName"" as ""ModifiedByName"",MT.""MealInstruction"",MT.""CreatedBy"",MT.""CreatedDate"",MT.""ModifiedBy"",MT.""ModifiedDate"",MT.""Active"" FROM ""MealTypes"" MT
                            LEFT JOIN ""Account"" A on A.""AccountId"" = MT.""CreatedBy""
                            LEFT JOIN ""Account"" M on M.""AccountId"" = MT.""ModifiedBy"" 
                               WHERE MT.""MealType"" ILIKE '%{term}%'";
            var records = await this.unitOfWork.Current.QueryAsync<Diet.MasterViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<ViewModel>> FetchMedicationAsync(FilterModel model)
        {
            var where = $@" AND to_char(M.""EndDate"", 'YYYY-MM-DD')::DATE >= '{(DateTime.Now.Date > model.EndDate?.Date ? model.EndDate : model.Date):yyyy-MM-dd}'::DATE";
            var query = $@"SELECT
	                        m.""ProgressReportId"",
	                        m.""ProgressReportMedicationId"",
	                        p.""PharmacyProductId"",
	                        m.""Unit"",
	                        m.""Duration"",
	                        m.""MedicationDurationTypeId"",
	                        m.""Active"",
	                        m.""StopReason"",
	                        m.""StartDate"",
	                        m.""EndDate"",
	                        m.""CreatedDate"",
	                        m.""ModifiedDate"",
	                        a.""FullName"" ""CreatedByName"",
	                        am.""FullName"" ""ModifiedByName"",
	                        m.""Instructions"",
	                        p.""ProductName"",
	                        p.""GenericName"" ""ProductGenericName"",
	                        c.""Name"" ""ProductCompanyName"",
	                        LOWER(v.""Name"") ""ProductTypeName"",
                            f.""ProgressReportMedicationFrequencyId"",
							mt.""MedicationInstructionTypeId"",
							mt.""Type"" ""MedicationInstructionDeepTypeId"",
							mt.""Name"" ""MedicationInstructionName"",
							d.""MedicationDate"",
							d.""Status""
                        FROM
	                        ""ProgressReportMedication"" M
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        JOIN ""PharmacyProduct"" p on p.""PharmacyProductId"" = m.""PharmacyProductId""
	                        JOIN ""LookupValue"" v on v.""LookupValueId"" = p.""CategoryId""
	                        JOIN ""Account"" a on a.""AccountId"" = m.""CreatedBy""
							LEFT JOIN ""ProgressReportMedicationFrequency"" f on f.""ProgressReportMedicationId"" = m.""ProgressReportMedicationId""
							LEFT JOIN ""ProgressReportMedicationDaily"" d on (d.""ProgressReportMedicationFrequencyId"" = f.""ProgressReportMedicationFrequencyId""
							        AND to_char(d.""MedicationDate"", 'YYYY-MM-DD')::DATE = '{model.Date:yyyy-MM-dd}'::DATE)
							LEFT JOIN ""MedicationInstructionType"" mt on f.""MedicationInstructionTypeId"" = mt.""MedicationInstructionTypeId""
	                        LEFT JOIN ""Account"" am on am.""AccountId"" = m.""ModifiedBy""
	                        LEFT JOIN ""Company"" c on c.""CompanyId"" = p.""CompanyId""
	                        WHERE r.""AdmissionId"" = {model.AdmissionId} {where}
	                        ORDER BY m.""ProgressReportMedicationId"" DESC";

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

        public async Task<IEnumerable<Timeline.MedicationViewModel>> FetchTimelineAsync(FilterModel model)
        {
            var whereQuery = model.AdmissionIds != null && model.AdmissionIds.Any()
                ? $@" r.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds.Select(x => x).ToArray())})"
                : $@" r.""AdmissionId"" = {model.AdmissionId}";

            var query = $@"SELECT
	                        r.""AdmissionId"",
	                        m.""ProgressReportId"",
	                        m.""ProgressReportMedicationId"",
	                        p.""PharmacyProductId"",
	                        m.""Unit"",
	                        m.""Duration"",
	                        m.""MedicationDurationTypeId"",
	                        m.""Active"",
	                        m.""StopReason"",
	                        m.""StartDate"",
	                        m.""EndDate"",
	                        m.""CreatedDate"",
	                        m.""ModifiedDate"",
	                        a.""FullName"" ""CreatedByName"",
	                        am.""FullName"" ""ModifiedByName"",
	                        m.""Instructions"",
	                        p.""ProductName"",
	                        p.""GenericName"" ""ProductGenericName"",
	                        c.""Name"" ""ProductCompanyName"",
	                        LOWER(v.""Name"") ""ProductTypeName"",
							mt.""MedicationInstructionTypeId"",
							mt.""Type"" ""MedicationInstructionDeepTypeId"",
							mt.""Name"" ""MedicationInstructionName"",
							mt.""Aditions"",
							f.""ProgressReportMedicationFrequencyId"",
                            d.""Status"",
                            pa.""Salutation"",
                            pa.""FullName"",
                            pa.""Age"",
                            pa.""Gender"",
                            pa.""UMRNo"",
                            pt.""Breakfast"",
                            pt.""Lunch"",
                            pt.""Dinner"",
                            mm.*,
                            (CASE WHEN pa.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.configuration.BucketURL}', pa.""Guid"", '/', pa.""ThumbnailUrl"") ELSE NULL END) AS ""PatientImage"" 
                        FROM
	                        ""ProgressReportMedication"" M
							JOIN ""ProgressReportMedicationFrequency"" f on f.""ProgressReportMedicationId"" = m.""ProgressReportMedicationId""
							JOIN ""MedicationInstructionType"" mt on mt.""MedicationInstructionTypeId"" = f.""MedicationInstructionTypeId""
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        JOIN ""Admission"" aa on aa.""AdmissionId"" = r.""AdmissionId""
	                        JOIN ""Patient"" pa on pa.""PatientId"" = aa.""PatientId""
	                        JOIN ""PharmacyProduct"" p on p.""PharmacyProductId"" = m.""PharmacyProductId""
	                        JOIN ""LookupValue"" v on v.""LookupValueId"" = p.""CategoryId""
                            LEFT JOIN ""ProgressReportMedicationDaily"" d on (d.""ProgressReportMedicationFrequencyId"" = f.""ProgressReportMedicationFrequencyId""
                                    AND to_char(d.""MedicationDate"", 'YYYY-MM-DD')::DATE = '{model.Date:yyyy-MM-dd}'::DATE)
	                        JOIN ""Account"" a on a.""AccountId"" = m.""CreatedBy""
                            LEFT JOIN ""PatientTiming"" pt on pt.""PatientId"" = pa.""PatientId""
	                        LEFT JOIN ""Account"" am on am.""AccountId"" = m.""ModifiedBy""
	                        LEFT JOIN ""Company"" c on c.""CompanyId"" = p.""CompanyId""

                            LEFT JOIN LATERAL(
								SELECT ""Hour"", ""Minute"" 
								FROM ""MedicationMove"" mm 
								WHERE mm.""ProgressReportMedicationFrequencyId"" = f.""ProgressReportMedicationFrequencyId""
								ORDER BY mm.""MedicationMoveId"" DESC
								LIMIT 1
							) mm on true

	                        WHERE {whereQuery}
                            AND (
			                        ('{model.Date:yyyy-MM-dd}'::DATE <= to_char(m.""EndDate"", 'YYYY-MM-DD' )::DATE ) 
			                        AND 
                                    ('{model.Date:yyyy-MM-dd}'::DATE >= to_char(m.""StartDate"", 'YYYY-MM-DD' )::DATE ) 
		                        ) 
                            AND (m.""Active"" IS TRUE OR to_char(m.""StopDate"", 'YYYY-MM-DD' )::DATE >= '{model.Date:yyyy-MM-dd}'::DATE)
                            ORDER BY mt.""Type"" ";
            var records = await this.unitOfWork.Current.QueryAsync<Timeline.MedicationViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<MedicationInfo.MedicationFetchModel>> FetchMedicationInfoAsync(FilterModel model)
        {
            var query = $@"SELECT
	                        r.""AdmissionId"",
							mt.""Type"" ""MedicationInstructionDeepTypeId"",
							mt.""Name"" ""MedicationInstructionName"",
                            d.""Status""
                        FROM
	                        ""ProgressReportMedication"" M
							JOIN ""ProgressReportMedicationFrequency"" f on f.""ProgressReportMedicationId"" = m.""ProgressReportMedicationId""
							JOIN ""MedicationInstructionType"" mt on mt.""MedicationInstructionTypeId"" = f.""MedicationInstructionTypeId""
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
                            LEFT JOIN ""ProgressReportMedicationDaily"" d on (d.""ProgressReportMedicationFrequencyId"" = f.""ProgressReportMedicationFrequencyId""
                                    AND to_char(d.""MedicationDate"", 'YYYY-MM-DD')::DATE = '{model.Date:yyyy-MM-dd}'::DATE)
	                        WHERE r.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds.Select(x => x).ToArray())})
                            AND (
			                        ('{model.Date:yyyy-MM-dd}'::DATE <= to_char(m.""EndDate"", 'YYYY-MM-DD' )::DATE ) 
			                        AND 
                                    ('{model.Date:yyyy-MM-dd}'::DATE >= to_char(m.""StartDate"", 'YYYY-MM-DD' )::DATE ) 
		                        ) 
                            AND (m.""Active"" IS TRUE OR to_char(m.""StopDate"", 'YYYY-MM-DD' )::DATE >= '{model.Date:yyyy-MM-dd}'::DATE)
                            ORDER BY mt.""Type"" ";
            var records = await this.unitOfWork.Current.QueryAsync<MedicationInfo.MedicationFetchModel>(query);
            return records;
        }

        public async Task<IEnumerable<Timeline.MedicationAllViewModel>> FetchAllTimelineAsync(FilterModel model)
        {
            var query = $@"SELECT A
	                            .*,
	                            d.""Status"" 
                            FROM
	                            (
	                            SELECT
		                            generate_series ( M.""StartDate"", COALESCE ( M.""StopDate"", M.""EndDate"" ), '1 day' ) :: DATE AS ""GeneralDate"",
		                            M.""StartDate"",
		                            M.""EndDate"",
		                            M.""StopDate"" :: DATE,
		                            P.""ProductName"",
		                            M.""ProgressReportId"",
		                            M.""ProgressReportMedicationId"",
		                            P.""PharmacyProductId"",
		                            M.""Unit"",
		                            M.""Duration"",
		                            M.""MedicationDurationTypeId"",
		                            M.""Active"",
		                            M.""StopReason"",
		                            M.""CreatedDate"",
		                            M.""ModifiedDate"",
		                            A.""FullName"" ""CreatedByName"",
		                            am.""FullName"" ""ModifiedByName"",
		                            M.""Instructions"",
		                            P.""GenericName"" ""ProductGenericName"",
		                            C.""Name"" ""ProductCompanyName"",
		                            LOWER ( v.""Name"" ) ""ProductTypeName"",
		                            mt.""MedicationInstructionTypeId"",
		                            mt.""Type"" ""MedicationInstructionDeepTypeId"",
		                            mt.""Name"" ""MedicationInstructionName"",
		                            f.""ProgressReportMedicationFrequencyId"",
                                    pa.""Salutation"",
                                    pa.""FullName"",
                                    pa.""Age"",
                                    pa.""Gender"",
                                    pa.""UMRNo""
	                            FROM
		                            ""ProgressReportMedication""
		                            M JOIN ""ProgressReportMedicationFrequency"" f ON f.""ProgressReportMedicationId"" = M.""ProgressReportMedicationId""
		                            JOIN ""MedicationInstructionType"" mt ON mt.""MedicationInstructionTypeId"" = f.""MedicationInstructionTypeId""
		                            JOIN ""ProgressReport"" r ON r.""ProgressReportId"" = M.""ProgressReportId""
                                    JOIN ""Admission"" aa on aa.""AdmissionId"" = r.""AdmissionId""
	                                JOIN ""Patient"" pa on pa.""PatientId"" = aa.""PatientId""
		                            JOIN ""PharmacyProduct"" P ON P.""PharmacyProductId"" = M.""PharmacyProductId""
		                            JOIN ""LookupValue"" v ON v.""LookupValueId"" = P.""CategoryId""
		                            JOIN ""Account"" A ON A.""AccountId"" = M.""CreatedBy""
		                            LEFT JOIN ""Account"" am ON am.""AccountId"" = M.""ModifiedBy""
		                            LEFT JOIN ""Company"" C ON C.""CompanyId"" = P.""CompanyId""
                                    LEFT JOIN ""Discharge"" d on d.""AdmissionId"" = aa.""AdmissionId""
	                            WHERE
		                            r.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds.Select(x => x).ToArray())}) AND d.""DischargeId"" IS NULL
	                            ORDER BY
		                            mt.""Type"" 
	                            )
	                            A LEFT JOIN ""ProgressReportMedicationDaily"" d ON ( d.""ProgressReportMedicationFrequencyId"" = A.""ProgressReportMedicationFrequencyId"" 
                                    AND to_char( d.""MedicationDate"", 'YYYY-MM-DD' ) :: DATE = A.""GeneralDate"" :: DATE ) ";
            var records = await this.unitOfWork.Current.QueryAsync<Timeline.MedicationAllViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<Timeline.ViewModel>> FetchTimelineSlotsAsync(List<int> model, DateTime date)
        {
            var query = $@"SELECT
	                        ""ProgressReportMedicationId"",
	                        ""MedicationInstructionTypeId"",
	                        ""Status""
                        FROM
	                        ""ProgressReportMedicationDaily""
                            WHERE ""ProgressReportMedicationId"" IN ({string.Join(",", model)}) AND to_char( ""MedicationDate"", 'YYYY-MM-DD' ) :: DATE = to_char( '{date:yyyy-MM-dd}'::DATE, 'YYYY-MM-DD' ) :: DATE ";

            var records = await this.unitOfWork.Current.QueryAsync<Timeline.ViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<TimelineViewModel>> FetchMedicationTimelineAsync(TimelineFilterModel model)
        {
            var query = $@"SELECT
	                        d.""MedicationDate"",
	                        t.""Type"",
	                        d.""Status"",
                            t.""Name""
                        FROM
	                        ""ProgressReportMedicationDaily"" d
	                        JOIN ""ProgressReportMedicationFrequency"" f on f.""ProgressReportMedicationFrequencyId"" = d.""ProgressReportMedicationFrequencyId""
	                        JOIN ""MedicationInstructionType"" t on t.""MedicationInstructionTypeId"" = f.""MedicationInstructionTypeId""
	                        JOIN ""ProgressReportMedication"" M ON M.""ProgressReportMedicationId"" = f.""ProgressReportMedicationId""
	                        JOIN ""ProgressReport"" r ON r.""ProgressReportId"" = M.""ProgressReportId"" 
                        WHERE
	                        r.""AdmissionId"" = {model.AdmissionId} 
	                        AND M.""ProgressReportMedicationId"" = {model.MedicineId}";
            var records = await this.unitOfWork.Current.QueryAsync<TimelineViewModel>(query);
            return records;
        }

        public async Task<DatesViewModel> FetchMedicationDatesAsync(FilterModel model)
        {
            var query = $@"select MIN(m.""StartDate"")::DATE, MAX(COALESCE(m.""StopDate"", m.""EndDate""))::DATE from ""ProgressReport"" r
                            JOIN ""ProgressReportMedication"" m on m.""ProgressReportId"" = r.""ProgressReportId""
                            WHERE r.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds)})";
            var records = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<DatesViewModel>(query);
            return records;
        }

        public async Task<IEnumerable<int>> FetchTopAdmissionIdsAsync(FilterModel model)
        {
            var query = $@"SELECT 
	                        DISTINCT a.""AdmissionId""
                        FROM
	                        ""NurseShiftBedMap""
	                        M JOIN ""NurseShiftMap"" n on n.""NurseShiftMapId"" = m.""NurseShiftMapId""
	                        JOIN ""Admission"" a on a.""BedId"" = m.""BedId""
	                        LEFT JOIN ""Discharge"" di ON di.""AdmissionId"" = A.""AdmissionId""
	                        WHERE n.""NurseAccountId"" = {model.Value} AND di.""DischargeId"" IS NULL AND A.""Active"" IS TRUE
                            AND (
			                        ('{model.Date:yyyy-MM-dd}'::DATE <= to_char(n.""ToDate"", 'YYYY-MM-DD' )::DATE ) 
			                        AND 
                                    ('{model.Date:yyyy-MM-dd}'::DATE >= to_char(n.""FromDate"", 'YYYY-MM-DD' )::DATE ) 
		                        ) ";
            var records = await this.unitOfWork.Current.QueryAsync<int>(query);
            return records;
        }

        public async Task<int> FetchMedicationCountAsync(General.FilterModel model)
        {
            var query = $@"SELECT COUNT(M.""ProgressReportMedicationId"") OVER() AS ""TotalItems""
                        FROM
	                        ""ProgressReportMedication"" M
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        WHERE r.""AdmissionId"" = {model.AdmissionId} AND m.""Active"" IS TRUE LIMIT 1";
            var records = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return records;
        }

        public async Task<int> FetchLabCountAsync(General.FilterModel model)
        {
            var query = $@"SELECT
	                            COUNT(LBH.""LabBookingDetailId"") OVER() AS ""TotalItems""
                            FROM
	                            ""LabBookingDetail"" LBH
                                JOIN ""LabBookingHeader"" h on h.""LabBookingHeaderId"" = LBH.""LabBookingHeaderId""
                            WHERE
	                            h.""AdmissionId"" = {model.AdmissionId} LIMIT 1";

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

        public async Task<int> FetchNotesCountAsync(General.FilterModel model)
        {
            var query = $@"SELECT COUNT(M.""ProgressReportNoteId"") OVER() AS ""TotalItems""
                        FROM
	                        ""ProgressReportNote"" M
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        WHERE r.""AdmissionId"" = {model.AdmissionId} AND M.""Active"" IS TRUE LIMIT 1";
            var records = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return records;
        }

        public async Task<int> FetchVitalsCountAsync(General.FilterModel model)
        {
            var query = $@"SELECT COUNT(M.""ProgressReportVitalsId"") OVER() AS ""TotalItems""
                        FROM
	                        ""ProgressReportVitals"" M
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        WHERE r.""AdmissionId"" = {model.AdmissionId} AND M.""Active"" IS TRUE LIMIT 1";
            var records = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return records;
        }

        public async Task<int> FetchAssessmentsCountAsync(General.FilterModel model)
        {
            var query = $@"SELECT COUNT(M.""ProgressReportAssessmentsId"") OVER() AS ""TotalItems""
                        FROM
	                        ""ProgressReportAssessments"" M
	                        JOIN ""ProgressReport"" r on r.""ProgressReportId"" = m.""ProgressReportId""
	                        WHERE r.""AdmissionId"" = {model.AdmissionId} AND M.""Active"" IS TRUE LIMIT 1";
            var records = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
            return records;
        }

        public async Task<IEnumerable<DateTime>> FetchLabDatesAsync(FilterModel model)
        {
            var query = $@"SELECT
	                            COALESCE(LBH.""LabDate"", h.""CreatedDate"")::DATE
                            FROM
	                            ""LabBookingDetail"" LBH
                                JOIN ""LabBookingHeader"" h on h.""LabBookingHeaderId"" = LBH.""LabBookingHeaderId""
                            WHERE
	                            h.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds)})";

            var records = await this.unitOfWork.Current.QueryAsync<DateTime>(query);
            return records;
        }

        public async Task<IEnumerable<DateTime>> FetchNoteDatesAsync(FilterModel model)
        {
            var query = $@"SELECT
	                            p.""Date""::DATE
                            FROM
	                            ""ProgressReportNote""
	                            P JOIN ""ProgressReport"" r ON r.""ProgressReportId"" = P.""ProgressReportId""
                            WHERE
	                            r.""AdmissionId"" IN ({string.Join(",", model.AdmissionIds)})";

            var records = await this.unitOfWork.Current.QueryAsync<DateTime>(query);
            return records;
        }

        public async Task<IEnumerable<DateTime>> FetchVitalsDatesAsync(FilterModel model)
        {
            var query = $@"SELECT
	                            p.""Date""::DATE
                            FROM
	                            ""ProgressReportVitals""
	                            P JOIN ""ProgressReport"" r ON r.""ProgressReportId"" = P.""ProgressReportId""
                            WHERE
	                            r.""AdmissionId"" = {model.AdmissionId}";

            var records = await this.unitOfWork.Current.QueryAsync<DateTime>(query);
            return records;
        }

        public async Task<IEnumerable<DateTime>> FetchAssessmentsDatesAsync(FilterModel model)
        {
            var query = $@"SELECT
	                            p.""Date""::DATE
                            FROM
	                            ""ProgressReportAssessments""
	                            P JOIN ""ProgressReport"" r ON r.""ProgressReportId"" = P.""ProgressReportId""
                            WHERE
	                            r.""AdmissionId"" = {model.AdmissionId}";

            var records = await this.unitOfWork.Current.QueryAsync<DateTime>(query);
            return records;
        }

        public async Task<IEnumerable<IndentMedicinesViewModel>> FetchIndentMedicationDatesAsync(FilterModel model)
        {
            var query = $@"SELECT
	                        d.""PharmacyProductId"",
	                        p.""ProductName"",
	                        LOWER(v.""Name"") ""ProductTypeName"" 
                        FROM
	                        ""PharmacyIndentHeader""  h
	                        JOIN ""PharmacyIndentDetail"" d on d.""PharmacyIndentHeaderId"" = h.""PharmacyIndentHeaderId""
	                        JOIN ""PharmacyProduct"" p on p.""PharmacyProductId"" = d.""PharmacyProductId""
	                        JOIN ""LookupValue"" v on v.""LookupValueId"" = p.""CategoryId""
                        WHERE
	                        ""AdmissionId"" = {model.AdmissionId} AND p.""PharmacyProductId"" NOT IN (
							SELECT m.""PharmacyProductId"" FROM ""ProgressReport"" r 
							JOIN ""ProgressReportMedication"" m on m.""ProgressReportId"" = r.""ProgressReportId""
							WHERE r.""AdmissionId"" = {model.AdmissionId}
						)";
            var records = await this.unitOfWork.Current.QueryAsync<IndentMedicinesViewModel>(query);
            return records;
        }


    }
}
