namespace Hims.Infrastructure.Services
{
    using System;
    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 InternalMedicineServices : IInternalMedicineService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

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

        /// <summary>
        /// The timeline service.
        /// </summary>
        private readonly ITimelineService timelineService;

        /// <inheritdoc cref="IInternalMedicineService"/>
        public InternalMedicineServices(ITimelineService timelineService, IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration)
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
            this.timelineService = timelineService;
        }

        /// <inheritdoc />
        public Task<InternalMedicineModel> FindAsync(int appointmentId, bool isAdmission)
        {
            var query = isAdmission
                ? $@"SELECT A.""AdmissionId"" ""AppointmentId"", A.""PatientId"", ec.""EncounterId"", ""ProblemList"", ""CheifComplaints"", ""FollowUp"", ""Medications"", ""Notes"", ""MedicationComment"",
                            ""Vitals"", ""Heent"", ""FamilyMedicalHistory"", ""SocialHistory"", ""Allergies"",""PreventiveCare"",""HospitalizationSurgery"",""Immunization"",""PastandCurrentMedications"",""CurrentMedications"",""Ros"",""Diagnosis"",""Musculoskeletal"",""Neurology"", ""Cardiovascular"" , ""Abdomen"",""EKG"",""GeneralAdvice"", ""Extremities"" as ""Extermities"",""Respiratory"",""Skin"", ATS.""Symptoms""
                            FROM ""Admission"" A
                            LEFT JOIN ""Encounter"" ec ON ec.""AdmissionId"" = A.""AdmissionId""
                            LEFT JOIN ""AppointmentSymptom"" ATS ON  ATS.""AdmissionId"" = A.""AdmissionId""
                            where A.""AdmissionId"" = '{appointmentId}' AND A.""Active"" IS TRUE"
                : $@"SELECT A.""AppointmentId"", A.""PatientId"", ec.""EncounterId"", ""ProblemList"", ""CheifComplaints"", ""FollowUp"", ""Medications"", ""Notes"", ""MedicationComment"",
                            ""Vitals"", ""Heent"", ""FamilyMedicalHistory"", ""SocialHistory"", ""Allergies"",""PreventiveCare"",""HospitalizationSurgery"",""Immunization"",""PastandCurrentMedications"",""CurrentMedications"",""Ros"",""Diagnosis"",""Musculoskeletal"",""Neurology"", ""Cardiovascular"" , ""Abdomen"",""EKG"",""GeneralAdvice"", ""Extremities"" as ""Extermities"",""Respiratory"",""Skin"", 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<InternalMedicineModel>(query);
        }

        /// <inheritdoc />
        public async Task<EncounterResource> FindDashboardAsync(int appointmentId, InternalMedicine type, bool isAdmission)
        {
            var encounter = isAdmission
                    ? await this.unitOfWork.Encounters.FindAsync(m => m.AdmissionId == appointmentId)
                    : 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;
                    case InternalMedicine.FamilyMedicalHistory:
                        encounterResource.JsonString = encounter.FamilyMedicalHistory;
                        break;
                    case InternalMedicine.SocialHistory:
                        encounterResource.JsonString = encounter.SocialHistory;
                        break;
                    case InternalMedicine.Diagnosis:
                        encounterResource.JsonString = encounter.Diagnosis;
                        break;
                    case InternalMedicine.GeneralAdvice:
                        encounterResource.JsonString = encounter.GeneralAdvice;
                        break;
                    case InternalMedicine.Heent:
                        encounterResource.JsonString = encounter.Heent;
                        break;
                    case InternalMedicine.Skin:
                        encounterResource.JsonString = encounter.Skin;
                        break;
                    case InternalMedicine.Abdomen:
                        encounterResource.JsonString = encounter.Abdomen;
                        break;
                    case InternalMedicine.Musculoskeletal:
                        encounterResource.JsonString = encounter.Musculoskeletal;
                        break;
                    case InternalMedicine.Neurology:
                        encounterResource.JsonString = encounter.Neurology;
                        break;
                    case InternalMedicine.Extremities:
                        encounterResource.JsonString = encounter.Extremities;
                        break;
                    case InternalMedicine.Respiratory:
                        encounterResource.JsonString = encounter.Respiratory;
                        break;
                    case InternalMedicine.Ekg:
                        encounterResource.JsonString = encounter.EKG;
                        break;
                    case InternalMedicine.CardioVascular:
                        encounterResource.JsonString = encounter.Cardiovascular;
                        break;
                    case InternalMedicine.Allergies:
                        encounterResource.JsonString = encounter.Allergies;
                        break;
                    case InternalMedicine.Hospitalization:
                        encounterResource.JsonString = encounter.HospitalizationSurgery;
                        break;
                    case InternalMedicine.PreventiveCare:
                        encounterResource.JsonString = encounter.PreventiveCare;
                        break;
                    case InternalMedicine.Immunizations:
                        encounterResource.JsonString = encounter.Immunization;
                        break;
                    case InternalMedicine.MedicationProblems:
                        encounterResource.JsonString = encounter.PastandCurrentMedications;
                        break;
                    case InternalMedicine.CurrentMedications:
                        encounterResource.JsonString = encounter.CurrentMedications;
                        break;
                    case InternalMedicine.ReviewOfSystems:
                        encounterResource.JsonString = encounter.Ros;
                        break;
                    

                }
            }

            return encounterResource;
        }

        /// <inheritdoc />
        public async Task<int> AddAsync(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,
                EncounterDate = DateTime.UtcNow,
                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.FamilyMedicalHistory:
                    encounter.FamilyMedicalHistory = model.JsonString;
                    break;
                case InternalMedicine.SocialHistory:
                    encounter.SocialHistory = model.JsonString;
                    break;
                case InternalMedicine.Diagnosis:
                    encounter.Diagnosis = model.JsonString;
                    break;
                case InternalMedicine.GeneralAdvice:
                    encounter.GeneralAdvice = model.JsonString;
                    break;
                case InternalMedicine.Heent:
                    encounter.Heent = model.JsonString;
                    break;
                case InternalMedicine.Skin:
                    encounter.Skin = model.JsonString;
                    break;
                case InternalMedicine.Abdomen:
                    encounter.Abdomen = model.JsonString;
                    break;
                case InternalMedicine.Musculoskeletal:
                    encounter.Musculoskeletal = model.JsonString;
                    break;
                case InternalMedicine.Neurology:
                    encounter.Neurology = model.JsonString;
                    break;
                case InternalMedicine.Extremities:
                    encounter.Extremities = model.JsonString;
                    break;
                case InternalMedicine.Respiratory:
                    encounter.Respiratory = model.JsonString;
                    break;
                case InternalMedicine.Ekg:
                    encounter.EKG = model.JsonString;
                    break;
                case InternalMedicine.CardioVascular:
                    encounter.Cardiovascular = model.JsonString;
                    break;
                case InternalMedicine.Allergies:
                    encounter.Allergies = model.JsonString;
                    break;
                case InternalMedicine.Hospitalization:
                    encounter.HospitalizationSurgery = model.JsonString;
                    break;
                case InternalMedicine.PreventiveCare:
                    encounter.PreventiveCare = model.JsonString;
                    break;
                case InternalMedicine.Immunizations:
                    encounter.Immunization = model.JsonString;
                    break;
                case InternalMedicine.MedicationProblems:
                    encounter.PastandCurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.CurrentMedications:
                    encounter.CurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.ReviewOfSystems:
                    encounter.Ros = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            var response = await this.unitOfWork.Encounters.InsertAsync(encounter);

            if (model.Type == InternalMedicine.Medications && response > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.MedicationsAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Medications added"
                });
            }
            else if (model.Type == InternalMedicine.Notes && response > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.NotesAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Notes added"
                });
            }
            else if (model.Type == InternalMedicine.FollowUp && response > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.FollowUpAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Follow Up added"
                });
            }


            return response;

        }

        /// <inheritdoc />
        public async Task<CommonResponse> AddAltAsync(EncounterModifyModel model)
        {
            var commonResponse = 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)
            {
                commonResponse.Response = -1;
                return commonResponse;
            }

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

            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;
                    commonResponse.Status = 2;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.FamilyMedicalHistory:
                    encounter.FamilyMedicalHistory = model.JsonString;
                    break;
                case InternalMedicine.SocialHistory:
                    encounter.SocialHistory = model.JsonString;
                    break;
                case InternalMedicine.Diagnosis:
                    encounter.Diagnosis = model.JsonString;
                    break;
                case InternalMedicine.GeneralAdvice:
                    encounter.GeneralAdvice = model.JsonString;
                    break;
                case InternalMedicine.Heent:
                    encounter.Heent = model.JsonString;
                    break;
                case InternalMedicine.Skin:
                    encounter.Skin = model.JsonString;
                    break;
                case InternalMedicine.Abdomen:
                    encounter.Abdomen = model.JsonString;
                    break;
                case InternalMedicine.Musculoskeletal:
                    encounter.Musculoskeletal = model.JsonString;
                    break;
                case InternalMedicine.Neurology:
                    encounter.Neurology = model.JsonString;
                    break;
                case InternalMedicine.Extremities:
                    encounter.Extremities = model.JsonString;
                    break;
                case InternalMedicine.Respiratory:
                    encounter.Respiratory = model.JsonString;
                    break;
                case InternalMedicine.Ekg:
                    encounter.EKG = model.JsonString;
                    break;
                case InternalMedicine.CardioVascular:
                    encounter.Cardiovascular = model.JsonString;
                    break;
                case InternalMedicine.Allergies:
                    encounter.Allergies = model.JsonString;
                    break;
                case InternalMedicine.Hospitalization:
                    encounter.HospitalizationSurgery = model.JsonString;
                    break;
                case InternalMedicine.PreventiveCare:
                    encounter.PreventiveCare = model.JsonString;
                    break;
                case InternalMedicine.Immunizations:
                    encounter.Immunization = model.JsonString;
                    break;
                case InternalMedicine.MedicationProblems:
                    encounter.PastandCurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.CurrentMedications:
                    encounter.CurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.ReviewOfSystems:
                    encounter.Ros = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
                
            }

            var response = await this.unitOfWork.Encounters.InsertAsync(encounter);

            if (model.Type == InternalMedicine.Medications && response > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.MedicationsAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Medications added"
                });
            }
            else if (model.Type == InternalMedicine.Notes && response > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.NotesAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Notes added"
                });
            }
            else if (model.Type == InternalMedicine.FollowUp && response > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.FollowUpAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Follow Up added"
                });
            }

            commonResponse.Response = response;

            return commonResponse;

        }

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

            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)
            {
                commonResponse.Response = -1;
                return commonResponse;
            }

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

            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;
                    commonResponse.Status = 2;
                    break;
                case InternalMedicine.Notes:
                    encounter.Notes = model.JsonString;
                    break;
                case InternalMedicine.Vitals:
                    encounter.Vitals = model.JsonString;
                    break;
                case InternalMedicine.FamilyMedicalHistory:
                    encounter.FamilyMedicalHistory = model.JsonString;
                    break;
                case InternalMedicine.SocialHistory:
                    encounter.SocialHistory = model.JsonString;
                    break;
                case InternalMedicine.Diagnosis:
                    encounter.Diagnosis = model.JsonString;
                    break;
                case InternalMedicine.GeneralAdvice:
                    encounter.GeneralAdvice = model.JsonString;
                    break;
                case InternalMedicine.Heent:
                    encounter.Heent = model.JsonString;
                    break;
                case InternalMedicine.Skin:
                    encounter.Skin = model.JsonString;
                    break;
                case InternalMedicine.Abdomen:
                    encounter.Abdomen = model.JsonString;
                    break;
                case InternalMedicine.Musculoskeletal:
                    encounter.Musculoskeletal = model.JsonString;
                    break;
                case InternalMedicine.Neurology:
                    encounter.Neurology = model.JsonString;
                    break;
                case InternalMedicine.Extremities:
                    encounter.Extremities = model.JsonString;
                    break;
                case InternalMedicine.Respiratory:
                    encounter.Respiratory = model.JsonString;
                    break;
                case InternalMedicine.Ekg:
                    encounter.EKG = model.JsonString;
                    break;
                case InternalMedicine.CardioVascular:
                    encounter.Cardiovascular = model.JsonString;
                    break;
                case InternalMedicine.Allergies:
                    encounter.Allergies = model.JsonString;
                    break;
                case InternalMedicine.Hospitalization:
                    encounter.HospitalizationSurgery = model.JsonString;
                    break;
                case InternalMedicine.PreventiveCare:
                    encounter.PreventiveCare = model.JsonString;
                    break;
                case InternalMedicine.Immunizations:
                    encounter.Immunization = model.JsonString;
                    break;
                case InternalMedicine.MedicationProblems:
                    encounter.PastandCurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.CurrentMedications:
                    encounter.CurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.ReviewOfSystems:
                    encounter.Ros = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
              
            }

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);

            if (model.Type == InternalMedicine.Medications && updated > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.MedicationsAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Medications added"
                });
            }
            else if (model.Type == InternalMedicine.Notes && updated > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.NotesUpdated,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Notes updated"
                });
            }
            else if (model.Type == InternalMedicine.FollowUp && updated > 0)
            {
                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;

                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = patientId,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    TimelineActionId = TimelineAction.FollowUpUpdated,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Follow Up added"
                });
            }

            commonResponse.Response = updated > 0 ? encounter.EncounterId : 0;

            return commonResponse;
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(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.FamilyMedicalHistory:
                    encounter.FamilyMedicalHistory = model.JsonString;
                    break;
                case InternalMedicine.SocialHistory:
                    encounter.SocialHistory = model.JsonString;
                    break;
                case InternalMedicine.Diagnosis:
                    encounter.Diagnosis = model.JsonString;
                    break;
                case InternalMedicine.GeneralAdvice:
                    encounter.GeneralAdvice = model.JsonString;
                    break;
                case InternalMedicine.Heent:
                    encounter.Heent = model.JsonString;
                    break;
                case InternalMedicine.Skin:
                    encounter.Skin = model.JsonString;
                    break;
                case InternalMedicine.Abdomen:
                    encounter.Abdomen = model.JsonString;
                    break;
                case InternalMedicine.Musculoskeletal:
                    encounter.Musculoskeletal = model.JsonString;
                    break;
                case InternalMedicine.Neurology:
                    encounter.Neurology = model.JsonString;
                    break;
                case InternalMedicine.Extremities:
                    encounter.Extremities = model.JsonString;
                    break;
                case InternalMedicine.Respiratory:
                    encounter.Respiratory = model.JsonString;
                    break;
                case InternalMedicine.Ekg:
                    encounter.EKG = model.JsonString;
                    break;
                case InternalMedicine.CardioVascular:
                    encounter.Cardiovascular = model.JsonString;
                    break;
                case InternalMedicine.Allergies:
                    encounter.Allergies = model.JsonString;
                    break;
                case InternalMedicine.Hospitalization:
                    encounter.HospitalizationSurgery = model.JsonString;
                    break;
                case InternalMedicine.PreventiveCare:
                    encounter.PreventiveCare = model.JsonString;
                    break;
                case InternalMedicine.Immunizations:
                    encounter.Immunization = model.JsonString;
                    break;
                case InternalMedicine.MedicationProblems:
                    encounter.PastandCurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.CurrentMedications:
                    encounter.CurrentMedications = model.JsonString;
                    break;
                case InternalMedicine.ReviewOfSystems:
                    encounter.Ros = model.JsonString;
                    break;
                case InternalMedicine.MedicationComments:
                    encounter.MedicationComment = model.JsonString;
                    break;
            }

            var updated = await this.unitOfWork.Encounters.UpdateAsync(encounter);

            if (model.Type == InternalMedicine.Medications && updated > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.AppointmentId,
                    TimelineActionId = TimelineAction.MedicationsAdded,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Medications added"
                });
            }
            else if (model.Type == InternalMedicine.Notes && updated > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.AppointmentId,
                    TimelineActionId = TimelineAction.NotesUpdated,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Notes updated"
                });
            }
            else if (model.Type == InternalMedicine.FollowUp && updated > 0)
            {
                var appointment = await this.unitOfWork.Appointments.FindAsync(x => x.AppointmentId == model.AppointmentId);
                await this.timelineService.LogAsync(new TimelineModel
                {
                    PatientId = appointment.PatientId,
                    AppointmentId = model.AppointmentId,
                    TimelineActionId = TimelineAction.FollowUpUpdated,
                    CreatedBy = model.ModifiedBy,
                    Data = model.JsonString,
                    Description = $"Follow Up added"
                });
            }

            return updated > 0 ? encounter.EncounterId : 0;
        }

        /// <inheritdoc />
        public Task<InternalMedicinePrescriptionModel> FindPrescriptionAsync(int appointmentId)
        {
            var query = $@"SELECT A.""AppointmentId"", A.""AppointmentNo"",Pr.""Educations"", A.""AppointmentDate"", A.""AppointmentTime"", ec.""EncounterId"", ec.""Medications"", ec.""FollowUp"", ec.""MedicationComment"",
							CONCAT(Pr.""Salutation"",' ', Pr.""FullName"") AS ""ProviderName"",Pr.""ProviderNo"",string_agg(S.""SpecializationName"",', ') ""SpecializationName"",P.""FullName"" AS ""PracticeName"",
							PrL.""Name"" AS ""PracticeLocation"",
							(case when A.""PatientFamilyId"" is not null then PF.""FullName"" else Pt.""FullName"" end) AS ""PatientName"",
                            (case when A.""PatientFamilyId"" is not null then PF.""Age"" else Pt.""Age"" end) AS ""PatientAge"",
                            (case when A.""PatientFamilyId"" is not null then PF.""Gender"" else Pt.""Gender"" end) AS ""PatientGender"",
							pt.""DateOfBirth"" AS ""PatientDateOfBirth"",CASE WHEN pt.""Mobile"" NOTNULL THEN CONCAT('(+', ct.""CountryCode"", ') ', pt.""Mobile"") ELSE NULL END AS ""PatientMobile"" FROM ""Appointment"" A
							JOIN ""Encounter"" ec ON ec.""AppointmentId""=A.""AppointmentId""
							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""
							JOIN ""Patient"" pt ON pt.""PatientId""=A.""PatientId""
                            left join ""PatientFamily"" PF on PF.""PatientFamilyId"" = A.""PatientFamilyId""
							LEFT JOIN ""Country"" ct ON ct.""CountryId""=pt.""CountryId""
                            where ec.""AppointmentId"" = {appointmentId} AND ec.""Active"" IS TRUE
							GROUP BY A.""AppointmentId"",A.""AppointmentDate"",A.""AppointmentTime"", ec.""EncounterId"", 
							ec.""Medications"", ec.""FollowUp"", ec.""MedicationComment"",""ProviderName"",Pr.""ProviderNo"",""PracticeName"",""PracticeLocation"",
							""PatientName"",""PatientAge"",""PatientGender"",""PatientDateOfBirth"",""PatientMobile"",Pr.""Educations"" ";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<InternalMedicinePrescriptionModel>(query);
        }

        /// <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"",
                             CONCAT(Pr.""Salutation"",' ', Pr.""FullName"") AS ""ProviderName"",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"",""Allergies"",""PreventiveCare"",""HospitalizationSurgery"",""Immunization"",""PastandCurrentMedications"",""CurrentMedications"",""Ros"",""SocialHistory"", ""Diagnosis"", ""GeneralAdvice"",""Heent"",""Extremities"",""Respiratory"",""EKG"", ""Musculoskeletal"",""Neurology"", ""Cardiovascular"" , ""Abdomen"",""Skin"",ATS.""Symptoms"" FROM ""Appointment"" A
							LEFT JOIN ""Encounter"" ec ON A.""AppointmentId""= ec.""AppointmentId""
							LEFT JOIN ""AppointmentSymptom"" ATS ON  ATS.""AppointmentId"" = A.""AppointmentId""
                            LEFT JOIN ""Provider"" pr on pr.""ProviderId""=A.""ProviderId""
							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);
        }

        /// <inheritdoc />
        public async Task<AppointmentModel> GetAccountBasedOnAppointmentId(long appointmentId, bool isAdmission)
        {
            var query = isAdmission
                ? $@"Select A.""PatientId"", A.""AdmissionNo"" ""AppointmentNo"", A.""AdmissionDate"" ""AppointmentDate"" from ""Admission"" A 
                                where A.""AdmissionId"" = {appointmentId}"
                : $@"Select A.""PatientId"", A.""AppointmentNo"", A.""AppointmentDate"", A.""AppointmentTime"" from ""Appointment"" A 
                                where A.""AppointmentId"" = {appointmentId}";

            var record = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<AppointmentModel>(query);
            if (isAdmission)
            {
                record.AppointmentTime = record.AppointmentDate.TimeOfDay;
            }

            return record;
        }
    }
}
