using System.Linq;
using Hims.Shared.UserModels.Filters;
using Hims.Shared.UserModels.Medications;

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

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

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

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

        /// <summary>
        /// The get doctor device tokens.
        /// </summary>
        /// <param name="appointmentId">
        /// The appointment id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public Task<IEnumerable<AccountSessionModel>> GetDoctorDeviceTokens(int appointmentId)
        {
            var query = $@"select DISTINCT acs.""DeviceToken"", acs.""DeviceType"" from ""Appointment"" a
                                    JOIN ""Account"" ac on ac.""ReferenceId"" = a.""ProviderId""
                                    JOIN ""AccountSession"" acs on acs.""AccountId"" = ac.""AccountId""
                                    WHERE a.""AppointmentId"" = '{appointmentId}' AND ac.""RoleId"" = 3 AND acs.""DeviceType"" != 1 ";
            return this.unitOfWork.Current.QueryAsync<AccountSessionModel>(query);
        }

        /// <summary>
        /// Gets the basic appointment details.
        /// </summary>
        /// <param name="appointmentId">The appointment identifier.</param>
        /// <param name="isAdmission">if set to <c>true</c> [is admission].</param>
        /// <returns></returns>
        public async Task<BasicAppointmentModel> GetBasicAppointmentDetails(int appointmentId, bool isAdmission)
        {
            var query = isAdmission
                ? $@"select a.""ProviderId"", a.""PatientId"" from ""Admission"" a
                                    WHERE a.""AdmissionId"" = '{appointmentId}' "
                : $@"select a.""ProviderId"", a.""PatientId"" from ""Appointment"" a
                                    WHERE a.""AppointmentId"" = '{appointmentId}' ";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<BasicAppointmentModel>(query);
        }

        /// <summary>
        /// The get uploader role.
        /// </summary>
        /// <param name="uploadedBy">
        /// The uploaded by.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<UploaderModel> GetUploaderRole(int uploadedBy)
        {
            var role = await this.unitOfWork.Accounts.FindAsync(x => x.AccountId == uploadedBy);
            return new UploaderModel { RoleId = role.RoleId, ReferenceId = role.ReferenceId };
        }

        /// <summary>
        /// The get uploader role.
        /// </summary>
        /// <param name="patientId">
        /// The patient Id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public async Task<BasicAppointmentModel> GetLatestAppointment(int patientId)
        {
            var query = $@"select a.""ProviderId"", a.""PatientId"" from ""Appointment"" a
                                    WHERE a.""PatientId"" = '{patientId}' ORDER BY ""AppointmentId"" DESC LIMIT 1 ";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<BasicAppointmentModel>(query);
        }

        /// <summary>
        /// The get patient device tokens.
        /// </summary>
        /// <param name="appointmentId">
        /// The appointment id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public Task<IEnumerable<AccountSessionModel>> GetPatientDeviceTokens(int appointmentId)
        {
            var query = $@"select DISTINCT acs.""DeviceToken"", acs.""DeviceType"" from ""Appointment"" a
                                    JOIN ""Account"" ac on ac.""ReferenceId"" = a.""PatientId""
                                    JOIN ""AccountSession"" acs on acs.""AccountId"" = ac.""AccountId""
                                    WHERE a.""AppointmentId"" = '{appointmentId}' AND ac.""RoleId"" = 4 AND acs.""DeviceType"" != 1 ";
            return this.unitOfWork.Current.QueryAsync<AccountSessionModel>(query);
        }

        /// <inheritdoc />
        public Task<EncounterModel> FindAsync(int encounterId)
        {
            var query = $@"SELECT * FROM ""Encounter"" ec where ec.""EncounterId"" = '{encounterId}' AND ec.""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<EncounterModel>(query);
        }

        /// <inheritdoc />
        public Task<EncounterModel> FindByAppointmentAsync(int appointmentId)
        {
            var query = $@"SELECT A.""AppointmentId"", ec.*, ATS.""Symptoms"" FROM ""Appointment"" A
                            LEFT JOIN ""Encounter"" ec ON ec.""AppointmentId"" = A.""AppointmentId""
                            LEFT JOIN ""AppointmentSymptom"" ATS ON  ATS.""AppointmentId"" = A.""AppointmentId""
                            where A.""AppointmentId"" = '{appointmentId}' AND A.""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<EncounterModel>(query);
        }

        /// <inheritdoc />
        public async Task<int> AddAsync(EncounterModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}'");
            if (checkIf > 0)
            {
                return -1;
            }

            var encounter = new Encounter
            {
                Active = true,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow,
                ProblemList = model.ProblemList,
                Radiology = model.Radiology,
                SocialHistory = model.SocialHistory,
                HospitalizationSurgery = model.HospitalizationSurgery,
                Immunization = model.Immunization,
                PreventiveCare = model.PreventiveCare,
                FamilyMedicalHistory = model.FamilyMedicalHistory,
                Respiratory = model.Respiratory,
                Skin = model.Skin,
                Abdomen = model.Abdomen,
                Neurology = model.Neurology,
                Vitals = model.Vitals,
                Cardiovascular = model.Cardiovascular,
                Extremities = model.Extremities,
                EKG = model.EKG,
                CheifComplaints = model.CheifComplaints,
                DischargeAdvice = model.DischargeAdvice,
                Diagnosis = model.Diagnosis,
                AppointmentId = model.IsAdmission ? null : (int?) model.AppointmentId,
                AdmissionId = model.IsAdmission ? (int?) model.AppointmentId : null,
                EncounterDate = DateTime.UtcNow,
                Heent = model.Heent,
                FollowUp = model.FollowUp,
                ICDcodes = model.ICDcodes,
                CPTcodes = model.CPTcodes,
                Medications = model.Medications,
                LabOrders = model.LabOrders,
                Allergies = model.Allergies,
                Musculoskeletal = model.Musculoskeletal,
                HistoryRadiology = model.HistoryRadiology,
                HistoryLaborder = model.HistoryLaborder,
                Ros = model.Ros,
                StressTest = model.StressTest,
                HPO = model.HPO,
                PastandCurrentMedications = model.PastandCurrentMedications,
                Angiogram = model.Angiogram,
                RecordsRequest = model.RecordsRequest,
                Consultations = model.Consultations,
                TOO = model.TOO,
                Notes = model.Notes
            };

            return await this.unitOfWork.Encounters.InsertAsync(encounter);
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(EncounterModel model)
        {
            var checkIf = model.IsAdmission 
            ? await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AdmissionId"" = '{model.AppointmentId}' AND ""EncounterId"" <> '{model.EncounterId}'")
            : await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""EncounterId"" <> '{model.EncounterId}'");

            if (checkIf > 0)
            {
                return -1;
            }

            var encounter = await this.unitOfWork.Encounters.FindAsync(m => m.EncounterId == model.EncounterId);
            encounter.AppointmentId = model.AppointmentId;
            encounter.Abdomen = model.Abdomen;
            encounter.Allergies = model.Allergies;
            encounter.Angiogram = model.Angiogram;
            encounter.CPTcodes = model.CPTcodes;
            encounter.Cardiovascular = model.Cardiovascular;
            encounter.CheifComplaints = model.CheifComplaints;
            encounter.Consultations = model.Consultations;
            encounter.Diagnosis = model.Diagnosis;
            encounter.DischargeAdvice = model.DischargeAdvice;
            encounter.EKG = model.EKG;
            encounter.Extremities = model.Extremities;
            encounter.FamilyMedicalHistory = model.FamilyMedicalHistory;
            encounter.FollowUp = model.FollowUp;
            encounter.HPO = model.HPO;
            encounter.Handouts = model.Handouts;
            encounter.Heent = model.Heent;
            encounter.HistoryLaborder = model.HistoryLaborder;
            encounter.HistoryRadiology = model.HistoryRadiology;
            encounter.HospitalizationSurgery = model.HospitalizationSurgery;
            encounter.Immunization = model.Immunization;
            encounter.ICDcodes = model.ICDcodes;
            encounter.LabOrders = model.LabOrders;
            encounter.Medications = model.Medications;
            encounter.Musculoskeletal = model.Musculoskeletal;
            encounter.Neurology = model.Neurology;
            encounter.PastandCurrentMedications = model.PastandCurrentMedications;
            encounter.PreventiveCare = model.PreventiveCare;
            encounter.ProblemList = model.ProblemList;
            encounter.Radiology = model.Radiology;
            encounter.RecordsRequest = model.RecordsRequest;
            encounter.Respiratory = model.Respiratory;
            encounter.Ros = model.Ros;
            encounter.Skin = model.Skin;
            encounter.SoapNotes = model.SoapNotes;
            encounter.SocialHistory = model.SocialHistory;
            encounter.StressTest = model.StressTest;
            encounter.TOO = model.TOO;
            encounter.Vitals = model.Vitals;
            encounter.Notes = model.Notes;
            encounter.ModifiedBy = model.ModifiedBy;
            encounter.ModifiedDate = DateTime.UtcNow;

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);
            return updated > 0 ? encounter.EncounterId : 0;
        }

        /// <inheritdoc />
        public async Task<CommonResponse> UpdateAltAsync(EncounterModel model)
        {
            var response = new CommonResponse { Status = 1 };

            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""EncounterId"" <> '{model.EncounterId}'");
            if (checkIf > 0)
            {
                response.Response = -1;
                return response;
            }

            var encounter = await this.unitOfWork.Encounters.FindAsync(m => m.EncounterId == model.EncounterId);
            encounter.AppointmentId = model.AppointmentId;
            encounter.Abdomen = model.Abdomen;
            encounter.Allergies = model.Allergies;
            encounter.Angiogram = model.Angiogram;
            encounter.CPTcodes = model.CPTcodes;
            encounter.Cardiovascular = model.Cardiovascular;
            encounter.CheifComplaints = model.CheifComplaints;
            encounter.Consultations = model.Consultations;
            encounter.Diagnosis = model.Diagnosis;
            encounter.DischargeAdvice = model.DischargeAdvice;
            encounter.EKG = model.EKG;
            encounter.Extremities = model.Extremities;
            encounter.FamilyMedicalHistory = model.FamilyMedicalHistory;
            encounter.FollowUp = model.FollowUp;
            encounter.HPO = model.HPO;
            encounter.Handouts = model.Handouts;
            encounter.Heent = model.Heent;
            encounter.HistoryLaborder = model.HistoryLaborder;
            encounter.HistoryRadiology = model.HistoryRadiology;
            encounter.HospitalizationSurgery = model.HospitalizationSurgery;
            encounter.Immunization = model.Immunization;
            encounter.ICDcodes = model.ICDcodes;
            encounter.LabOrders = model.LabOrders;

            if (encounter.Medications != model.Medications)
            {
                response.Status = 2;
            }

            encounter.Medications = model.Medications;
            encounter.Musculoskeletal = model.Musculoskeletal;
            encounter.Neurology = model.Neurology;
            encounter.PastandCurrentMedications = model.PastandCurrentMedications;
            encounter.PreventiveCare = model.PreventiveCare;
            encounter.ProblemList = model.ProblemList;
            encounter.Radiology = model.Radiology;
            encounter.RecordsRequest = model.RecordsRequest;
            encounter.Respiratory = model.Respiratory;
            encounter.Ros = model.Ros;
            encounter.Skin = model.Skin;
            encounter.SoapNotes = model.SoapNotes;
            encounter.SocialHistory = model.SocialHistory;
            encounter.StressTest = model.StressTest;
            encounter.TOO = model.TOO;
            encounter.Vitals = model.Vitals;
            encounter.Notes = model.Notes;
            encounter.ModifiedBy = model.ModifiedBy;
            encounter.ModifiedDate = DateTime.UtcNow;

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);
            response.Response = updated > 0 ? encounter.EncounterId : 0;
            return response;
        }

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

        /// <inheritdoc />
        public Task<AppointmentModel> FindPatientAsync(int encounterId)
        {
            var query = $@"select a.""AppointmentId"",p.""FullName"" AS ""PatientName"",pr.""FullName"" AS ""ProviderName"",p.""UMRNo"",p.""Email"" AS ""PatientEmail"",p.""Mobile"" AS ""PatientMobile"",a.""AppointmentNo"",a.""AppointmentDate"",a.""AppointmentTime"" from  ""Appointment"" a
                            join  ""Patient"" p on p.""PatientId""=a.""PatientId""
                            join ""Provider"" pr on a.""ProviderId""=pr.""ProviderId""
                            join ""Encounter"" e on e.""AppointmentId""=a.""AppointmentId""
                            where ""EncounterId""={encounterId}";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<AppointmentModel>(query);
        }

        /// <inheritdoc />
        public async Task<EncounterResource> FindEncounterAsync(int appointmentId, InternalMedicine type)
        {
            var encounter = await this.unitOfWork.Encounters.FindAsync(m => m.AppointmentId == appointmentId);
            var encounterResource = new EncounterResource
            {
                AppointmentId = appointmentId,
                EncounterId = null,
                JsonString = null
            };

            if (encounter != null)
            {
                encounterResource.EncounterId = encounter.EncounterId;
                switch (type)
                {
                    case InternalMedicine.ProblemList:
                        encounterResource.JsonString = encounter.ProblemList;
                        break;
                    case InternalMedicine.CheifComplaints:
                        encounterResource.JsonString = encounter.CheifComplaints;
                        break;
                    case InternalMedicine.FollowUp:
                        encounterResource.JsonString = encounter.FollowUp;
                        break;
                    case InternalMedicine.Medications:
                        encounterResource.JsonString = encounter.Medications;
                        encounterResource.MedicationComment = encounter.MedicationComment;
                        break;
                    case InternalMedicine.Notes:
                        encounterResource.JsonString = encounter.Notes;
                        break;
                    case InternalMedicine.Vitals:
                        encounterResource.JsonString = encounter.Vitals;
                        break;
                }
            }

            return encounterResource;
        }

        /// <inheritdoc />
        public async Task<int> AddEncounterAsync(EncounterModifyModel model)
        {
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}'");
            if (checkIf > 0)
            {
                return -1;
            }

            var encounter = new Encounter
            {
                Active = true,
                AppointmentId = model.AppointmentId,
                CreatedBy = model.ModifiedBy,
                CreatedDate = DateTime.UtcNow
            };

            switch (model.Type)
            {
                case InternalMedicine.ProblemList:
                    encounter.ProblemList = model.JsonString;
                    break;
                case InternalMedicine.CheifComplaints:
                    encounter.CheifComplaints = model.JsonString;
                    break;
                case InternalMedicine.FollowUp:
                    encounter.FollowUp = model.JsonString;
                    break;
                case InternalMedicine.Medications:
                    encounter.Medications = model.JsonString;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            return await this.unitOfWork.Encounters.InsertAsync(encounter);
        }

        /// <inheritdoc />
        public async Task<CommonResponse> AddEncounterAltAsync(EncounterModifyModel model)
        {
            var response = new CommonResponse { Status = 1 };
            var checkIf = model.IsAdmission 
                ? await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AdmissionId"" = '{model.AppointmentId}'")
                : await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}'");

            if (checkIf > 0)
            {
                response.Response = -1;
                return response;
            }

            var encounter = new Encounter
            {
                Active = true,
                AppointmentId = model.IsAdmission ? null : (int?) model.AppointmentId,
                AdmissionId = model.IsAdmission ? (int?) model.AppointmentId : null,
                CreatedBy = model.ModifiedBy,
                CreatedDate = DateTime.UtcNow
            };

            switch (model.Type)
            {
                case InternalMedicine.ProblemList:
                    encounter.ProblemList = model.JsonString;
                    break;
                case InternalMedicine.CheifComplaints:
                    encounter.CheifComplaints = model.JsonString;
                    break;
                case InternalMedicine.FollowUp:
                    encounter.FollowUp = model.JsonString;
                    break;
                case InternalMedicine.Medications:
                    encounter.Medications = model.JsonString;
                    response.Status = 2;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            response.Response = await this.unitOfWork.Encounters.InsertAsync(encounter);
            return response;
        }

        /// <inheritdoc />
        public async Task<int> UpdateEncounterAsync(EncounterModifyModel model)
        {
            var encounter = await this.unitOfWork.Encounters.FindAsync(m => m.EncounterId == model.EncounterId);

            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""EncounterId"" <> '{model.EncounterId}'");
            if (checkIf > 0)
            {
                return -1;
            }

            encounter.ModifiedBy = model.ModifiedBy;
            encounter.ModifiedDate = DateTime.UtcNow;

            switch (model.Type)
            {
                case InternalMedicine.ProblemList:
                    encounter.ProblemList = model.JsonString;
                    break;
                case InternalMedicine.CheifComplaints:
                    encounter.CheifComplaints = model.JsonString;
                    break;
                case InternalMedicine.FollowUp:
                    encounter.FollowUp = model.JsonString;
                    break;
                case InternalMedicine.Medications:
                    encounter.Medications = model.JsonString;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);
            return updated > 0 ? encounter.EncounterId : 0;
        }

        /// <inheritdoc />
        public async Task<CommonResponse> UpdateEncounterAltAsync(EncounterModifyModel model)
        {
            var response = new CommonResponse { Status = 1 };
            var encounter = await this.unitOfWork.Encounters.FindAsync(m => m.EncounterId == model.EncounterId);

            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""EncounterId"") FROM ""Encounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""EncounterId"" <> '{model.EncounterId}'");
            if (checkIf > 0)
            {
                response.Response = -1;
                return response;
            }

            encounter.ModifiedBy = model.ModifiedBy;
            encounter.ModifiedDate = DateTime.UtcNow;

            switch (model.Type)
            {
                case InternalMedicine.ProblemList:
                    encounter.ProblemList = model.JsonString;
                    break;
                case InternalMedicine.CheifComplaints:
                    encounter.CheifComplaints = model.JsonString;
                    break;
                case InternalMedicine.FollowUp:
                    encounter.FollowUp = model.JsonString;
                    break;
                case InternalMedicine.Medications:
                    encounter.Medications = model.JsonString;
                    response.Status = 2;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);
            response.Response = updated > 0 ? encounter.EncounterId : 0;
            return response;
        }

        /// <inheritdoc />
        public Task<InternalMedicineFullTranscriptModel> FindFullTranscriptAsync(int appointmentId)
        {
            var query = $@"SELECT A.""AppointmentId"",A.""AppointmentNo"", A.""AppointmentDate"",A.""AppointmentTime"", 
                            (case when A.""PatientFamilyId"" is not null then PF.""FullName"" else P.""FullName"" end) AS ""PatientName"", 
                           (case when A.""PatientFamilyId"" is not null then PF.""Gender"" else P.""Gender"" end)  AS ""PatientGender"",C.""CountryCode"" AS ""PatientCountryCode"",
							P.""Mobile"" AS ""PatientMobile"",
                            (case when A.""PatientFamilyId"" is not null then PF.""Age"" else P.""Age"" end) AS ""PatientAge"", P.""DateOfBirth"" AS ""PatientDateOfBirth"",
							(CASE WHEN P.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE NULL END) AS ""PatientThumbnailUrl"",
							""EncounterId"", ""ProblemList"", ""CheifComplaints"", ""FollowUp"", ""Medications"", ""Notes"", ""Vitals"", ""MedicationComment"",
							""FamilyMedicalHistory"", ""SocialHistory"", ""Diagnosis"", ""GeneralAdvice"", ATS.""Symptoms"" FROM ""Appointment"" A
							LEFT JOIN ""Encounter"" ec ON A.""AppointmentId""= ec.""AppointmentId""
							LEFT JOIN ""AppointmentSymptom"" ATS ON  ATS.""AppointmentId"" = A.""AppointmentId""
							JOIN ""Patient"" P ON P.""PatientId"" = A.""PatientId""
                            Left join ""PatientFamily"" PF on PF.""PatientFamilyId"" = A.""PatientFamilyId""
							LEFT JOIN ""Country"" C ON C.""CountryId"" = P.""CountryId""
                            where A.""AppointmentId"" = {appointmentId} AND A.""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<InternalMedicineFullTranscriptModel>(query);
        }

        /// <summary>
        /// The fetch active medications.
        /// </summary>
        /// <param name="patientId">
        /// The patient Id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        public Task<MedicationsModel> FetchActiveMedications(int patientId)
        {
            var query = $@"select a.""AppointmentId"", e.""Medications"", e.""CreatedDate"", e.""ModifiedDate"" from ""Appointment"" a 
                            JOIN ""Encounter"" e on e.""AppointmentId"" = a.""AppointmentId""
                            WHERE ""PatientId"" = {patientId} AND a.""Active"" IS TRUE AND e.""Medications"" IS NOT NULL
                            order by ""AppointmentDate"" DESC LIMIT 1 ";
            return this.unitOfWork.Current.QuerySingleOrDefaultAsync<MedicationsModel>(query);
        }

        /// <inheritdoc />
        public async Task<IEnumerable<VitalsModel>> FetchVitals(EncounterFilterModel model)
        {
            var patientId = model.IsAdmission
                ? (await this.unitOfWork.Admission.FindAsync(x => x.AdmissionId == model.AppointmentId)).PatientId
                : (await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId)).PatientId;

            var idsQuery = model.IsAdmission
                ? $@"SELECT ""AdmissionId"" FROM ""Admission"" where ""PatientId"" = {patientId}"
                : $@"SELECT ""AppointmentId"" FROM ""Appointment"" where ""PatientId"" = {patientId}";
            var idsArray = await this.unitOfWork.Current.QueryAsync<int>(idsQuery);
            var ids = string.Join(",", idsArray);

            var query = model.IsAdmission
                ? $@"Select count(*) over() as TotalItems, A.""AdmissionDate""::text ,to_char(A.""AdmissionDate""::time, 'hh12:mi PM') ""AppointmentTime"", E.""Vitals"" from ""Encounter"" E join ""Admission"" A on A.""AdmissionId"" = E.""AdmissionId"" Where E.""Vitals"" is not null And A.""AdmissionId"" in ({ids}) order by A.""AdmissionDate"" desc"
                : $@"Select count(*) over() as TotalItems, A.""AppointmentDate""::text ,to_char(A.""AppointmentTime""::time, 'hh12:mi PM') ""AppointmentTime"", E.""Vitals"" from ""Encounter"" E join ""Appointment"" A on A.""AppointmentId"" = E.""AppointmentId"" Where E.""Vitals"" is not null And A.""AppointmentId"" in ({ids}) order by A.""AppointmentDate"" desc";
            if (model.PageIndex <= 0)
            {
                return await this.unitOfWork.Current.QueryAsync<VitalsModel>(query);
            }

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

        /// <inheritdoc />
        public async Task<InternalMedicinePrescriptionModel> GetAdditionalProviderDataAsync(int appointmentId)
        {
            var query = $@"SELECT Pr.""Educations"",	CONCAT(Pr.""Salutation"",' ', Pr.""FullName"") AS ""ProviderName"",Pr.""ProviderNo"",string_agg(S.""SpecializationName"",', ') ""SpecializationName"",P.""FullName"" AS ""PracticeName"",
							PrL.""Name"" AS ""PracticeLocation"",
							(CASE WHEN Pr.""Signature"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', Pr.""Guid"", '/', Pr.""Signature"") ELSE NULL END) AS ""Signature"",
                            (CASE WHEN Pr.""ClinicPicture"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', Pr.""Guid"", '/', Pr.""ClinicPicture"") ELSE NULL END) AS ""ClinicPicture""       
							FROM ""Appointment"" A							
							JOIN ""Provider"" Pr ON Pr.""ProviderId""=A.""ProviderId""
							JOIN ""Specialization"" S ON S.""SpecializationId"" =ANY(Pr.""Specializations"")
							JOIN ""ProviderLocation"" PL ON PL.""ProviderLocationId"" = A.""ProviderLocationId""
							JOIN ""Location"" PrL ON PrL.""LocationId"" =PL.""LocationId""
							JOIN ""Practice"" P ON P.""PracticeId"" = PrL.""PracticeId""							                            						
                            where A.""AppointmentId"" = {appointmentId} AND A.""Active"" IS TRUE
							GROUP BY ""ProviderName"",Pr.""ProviderNo"",""PracticeName"",""PracticeLocation"",
							Pr.""Educations"",Pr.""Guid"",Pr.""Signature"",Pr.""ClinicPicture"" ";

            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<InternalMedicinePrescriptionModel>(query);
        }
    }
}
