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;
    using Hims.Shared.UserModels.PediatricEncounter;
    using pediatric = Shared.UserModels.PediatricEncounter;
    using System.Collections;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Reflection.PortableExecutable;

    /// <inheritdoc />
    public class PediatricEncounterServices : IPediatricEncounterService
    {
        /// <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;

        private readonly IAuditLogService auditLogService;

        /// <inheritdoc cref="IGynEncounterService"/>
        public PediatricEncounterServices(ITimelineService timelineService, IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration, IAuditLogService auditLogService)
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
            this.timelineService = timelineService;
            this.auditLogService = auditLogService;
        }

        public async Task<CommonResponse> AddAsync(pediatric.InsertModel model)
        {
            try
            {
                var commonResponse = new CommonResponse { Status = 1 };
                var checkIf = model.IsAdmission
                    ? await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PediatricEncounterId"") FROM ""PediatricEncounter"" WHERE ""AdmissionId"" = {model.AppointmentId}")
                    : await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PediatricEncounterId"") FROM ""PediatricEncounter"" WHERE ""AppointmentId"" = {model.AppointmentId}");
                if (checkIf > 0)
                {
                    commonResponse.Response = -1;
                    return commonResponse;
                }
                var admission = new Admission();
                var appointment = new Appointment();
                if (model.IsAdmission)
                {
                    admission = this.unitOfWork.Admission.Find(s => s.AdmissionId == model.AppointmentId);
                }
                else
                {
                    appointment = this.unitOfWork.Appointments.Find(s => s.AppointmentId == model.AppointmentId);
                }

                var encounter = new PediatricEncounter
                {
                    Active = true,
                    AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,

                    AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                    PediatricEncounterDate = DateTime.Now,
                    CreatedBy = model.ModifiedBy,
                    CreatedDate = DateTime.Now,
                    PatientId = model.IsAdmission ? admission.PatientId : appointment.PatientId


                };

                switch (model.Type)
                {
                    case PediatricEncounterType.Measurements:
                        encounter.Measurements = model.JsonString;
                        break;
                    case PediatricEncounterType.NeonatalRisk:
                        encounter.NeonatalRisk = model.JsonString;
                        break;
                    case PediatricEncounterType.PediatricRisk:
                        encounter.PediatricRisk = model.JsonString;
                        break;
                    case PediatricEncounterType.Syndrome:
                        encounter.Syndrome = model.JsonString;
                        break;
                    case PediatricEncounterType.ClinicalExamination:
                        encounter.ClinicalExamination = model.JsonString;
                        break;
                    case PediatricEncounterType.DownSyndromeFollowUp:
                        encounter.DownSyndromeFollowUp = model.JsonString;
                        break;
                    case PediatricEncounterType.HighRiskIntial:
                        encounter.HighRiskIntial = model.JsonString;
                        break;
                    case PediatricEncounterType.PediatricGuide:
                        encounter.PediatricGuide = model.JsonString;
                        break;
                    case PediatricEncounterType.OrderPrescription:
                        encounter.OrderPrescription = model.JsonString;
                        break;
                    case PediatricEncounterType.Allergies:
                        encounter.Allergies = model.JsonString;
                        break;
                    case PediatricEncounterType.VaccineDetail:
                        encounter.VaccineDetail = model.JsonString;
                        break;
                    case PediatricEncounterType.MChat:
                        encounter.MChat = model.JsonString;
                        break;


                    case PediatricEncounterType.SpecialFeatures:
                        encounter.SpecialFeatures = model.JsonString;
                        break;
                    case PediatricEncounterType.Reminder:
                        encounter.Reminder = model.JsonString;
                        break;
                }

                if (model.Type == PediatricEncounterType.Measurements)
                {
                    encounter.MeasureCommonData = model.JsonString;
                }
                if (model.RefferalOrder != null || model.DiagnosisOrder != null || model.NextVisitOrder != null)
                {
                    encounter.RefferalOrder = model.RefferalOrder != null ? model.RefferalOrder : null;
                    encounter.DiagnosisOrder = model.DiagnosisOrder != null ? model.DiagnosisOrder : null;
                    encounter.NextVisitOrder = model.NextVisitOrder != null ? model.NextVisitOrder : null;

                }
                var response = await this.unitOfWork.PediatricEncounters.InsertAsync(encounter);
                commonResponse.Response = response;
                if (response > 0)
                {
                    var auditLog = new AuditLogModel
                    {
                        LogTypeId = (int)LogTypes.PediatricEncounter,
                        AccountId = model.CreatedBy,
                        LogDescription = "PediatricEncounter Has been added"
                    };
                 

                await this.auditLogService.LogAsync(auditLog);
            }
                return commonResponse;
            }
            catch (Exception ex)
            {
                return null;
            }
        }
        public async Task<CommonResponse> UpdateAsync(InsertModel model)
        {
            var commonResponse = new CommonResponse { Status = 1 };
            var encounter = await this.unitOfWork.PediatricEncounters.FindAsync(m => m.PediatricEncounterId == model.PediatricEncounterId);

            var checkIf = model.IsAdmission
                    ? await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PediatricEncounterId"") FROM ""PediatricEncounter"" WHERE ""AdmissionId"" = '{model.AppointmentId}' AND ""PediatricEncounterId"" <> '{model.PediatricEncounterId}'")
                    : await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""PediatricEncounterId"") FROM ""PediatricEncounter"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""PediatricEncounterId"" <> '{model.PediatricEncounterId}'");

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

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

            switch (model.Type)
            {
                case PediatricEncounterType.Measurements:
                    encounter.Measurements = model.JsonString;
                    break;
                case PediatricEncounterType.NeonatalRisk:
                    encounter.NeonatalRisk = model.JsonString;
                    break;
                case PediatricEncounterType.PediatricRisk:
                    encounter.PediatricRisk = model.JsonString;
                    break;
                case PediatricEncounterType.Syndrome:
                    encounter.Syndrome = model.JsonString;
                    break;
                case PediatricEncounterType.ClinicalExamination:
                    encounter.ClinicalExamination = model.JsonString;
                    break;
                case PediatricEncounterType.DownSyndromeFollowUp:
                    encounter.DownSyndromeFollowUp = model.JsonString;
                    break;
                case PediatricEncounterType.HighRiskIntial:
                    encounter.HighRiskIntial = model.JsonString;
                    break;
                case PediatricEncounterType.PediatricGuide:
                    encounter.PediatricGuide = model.JsonString;
                    break;
                case PediatricEncounterType.OrderPrescription:
                    encounter.OrderPrescription = model.JsonString;
                    break;
                case PediatricEncounterType.Allergies:
                    encounter.Allergies = model.JsonString;
                    break;
                case PediatricEncounterType.VaccineDetail:
                    encounter.VaccineDetail = model.JsonString;
                    break;
                case PediatricEncounterType.MChat:
                    encounter.MChat = model.JsonString;
                    break;

                case PediatricEncounterType.SpecialFeatures:
                    encounter.SpecialFeatures = model.JsonString;
                    break;
                case PediatricEncounterType.Reminder:
                    encounter.Reminder = model.JsonString;
                    break;
                    break;
                    if (model.Type == PediatricEncounterType.Measurements)
                    {
                        encounter.MeasureCommonData = model.JsonString;
                    }
            }
            if (model.RefferalOrder != null || model.DiagnosisOrder != null || model.NextVisitOrder != null)
            {
                encounter.RefferalOrder = model.RefferalOrder != null ? model.RefferalOrder : null;
                encounter.DiagnosisOrder = model.DiagnosisOrder != null ? model.DiagnosisOrder : null;
                encounter.NextVisitOrder = model.NextVisitOrder != null ? model.NextVisitOrder : null;

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

            commonResponse.Response = updated > 0 ? encounter.PediatricEncounterId : 0;
            return commonResponse;
        }

        public async Task<PediatricEncounterResource> FindDashboardAsync(int appointmentId, PediatricEncounterType type, bool isAdmission)
        {
            try
            {

                var pediatricEncounter = isAdmission
                                   ? await this.unitOfWork.PediatricEncounters.FindAsync(m => m.AdmissionId == appointmentId)
                                   : await this.unitOfWork.PediatricEncounters.FindAsync(m => m.AppointmentId == appointmentId);

                var pediatricEncounterResource = new PediatricEncounterResource
                {
                    AppointmentId = appointmentId,
                    PediatricEncounterId = null,
                    JsonString = null
                };

                if (pediatricEncounter != null)
                {
                    pediatricEncounterResource.PediatricEncounterId = pediatricEncounter.PediatricEncounterId;
                    switch (type)
                    {
                        case PediatricEncounterType.Measurements:
                            pediatricEncounterResource.JsonString = pediatricEncounter.Measurements;
                            break;
                        case PediatricEncounterType.NeonatalRisk:
                            pediatricEncounterResource.JsonString = pediatricEncounter.NeonatalRisk;
                            break;
                        case PediatricEncounterType.PediatricRisk:
                            pediatricEncounterResource.JsonString = pediatricEncounter.PediatricRisk;
                            break;
                        case PediatricEncounterType.Syndrome:
                            pediatricEncounterResource.JsonString = pediatricEncounter.Syndrome;
                            break;
                        case PediatricEncounterType.ClinicalExamination:
                            pediatricEncounterResource.JsonString = pediatricEncounter.ClinicalExamination;
                            break;
                        case PediatricEncounterType.DownSyndromeFollowUp:
                            pediatricEncounterResource.JsonString = pediatricEncounter.DownSyndromeFollowUp;
                            break;

                        case PediatricEncounterType.HighRiskIntial:
                            pediatricEncounterResource.JsonString = pediatricEncounter.HighRiskIntial;
                            break;

                        case PediatricEncounterType.PediatricGuide:
                            pediatricEncounterResource.JsonString = pediatricEncounter.PediatricGuide;
                            break;

                        case PediatricEncounterType.OrderPrescription:
                            pediatricEncounterResource.JsonString = pediatricEncounter.OrderPrescription;
                            break;

                        case PediatricEncounterType.Allergies:
                            pediatricEncounterResource.JsonString = pediatricEncounter.Allergies;
                            break;
                        case PediatricEncounterType.VaccineDetail:
                            pediatricEncounterResource.JsonString = pediatricEncounter.VaccineDetail;
                            break;
                        case PediatricEncounterType.MChat:
                            pediatricEncounterResource.JsonString = pediatricEncounter.MChat;
                            break;
                        case PediatricEncounterType.DiagnosisOrder:
                            pediatricEncounterResource.JsonString = pediatricEncounter.DiagnosisOrder;
                            break;
                        case PediatricEncounterType.RefferalOrder:
                            pediatricEncounterResource.JsonString = pediatricEncounter.RefferalOrder;
                            break;
                        case PediatricEncounterType.NextVisitOrder:
                            pediatricEncounterResource.JsonString = pediatricEncounter.NextVisitOrder;
                            break;

                        case PediatricEncounterType.SpecialFeatures:
                            pediatricEncounterResource.JsonString = pediatricEncounter.SpecialFeatures;
                            break;

                        case PediatricEncounterType.Reminder:
                            pediatricEncounterResource.JsonString = pediatricEncounter.Reminder;
                            break;
                    }
                }

                return pediatricEncounterResource;
            }
            catch (Exception ex)
            {
                throw;
            }

        }

        /// <inheritdoc />
        public async Task<PediatricEncounterModel> FindAsync(int appointmentId, bool isAdmission)
        {
            var result = new PediatricEncounterModel();
            if (appointmentId != 0)
            {
                var query = "";
                var getId = 0;
                var addRecords = new Admission();
                var appRecord = new Appointment();
                if (isAdmission)
                {
                    addRecords = this.unitOfWork.Admission.Find(s => s.AdmissionId == appointmentId);
                    getId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(*) FROM ""PediatricEncounter"" WHERE ""AdmissionId"" = {addRecords.AdmissionId}");
                }
                else
                {
                    appRecord = this.unitOfWork.Appointments.Find(s => s.AppointmentId == appointmentId);
                    if (appRecord != null)
                    {
                        getId = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(*) FROM ""PediatricEncounter"" WHERE ""AppointmentId"" = {appRecord.AppointmentId}");
                    }
                }
                if (getId == 0)
                {
                    var AptCnt = 0;
                    if (isAdmission)
                    {
                        query = $@"select * from ""PediatricEncounter"" where ""PatientId""={addRecords.PatientId} order by 1 desc ";
                        AptCnt = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(*) FROM ""PediatricEncounter"" WHERE ""PatientId"" = {addRecords.PatientId}");
                    }
                    else
                    {
                        if (appRecord != null && appRecord.PatientId != 0)
                        {
                            query = $@"select * from ""PediatricEncounter"" where ""PatientId""={appRecord.PatientId} order by 1 desc ";
                            AptCnt = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(*) FROM ""PediatricEncounter"" WHERE ""PatientId"" = {appRecord.PatientId}");

                        }
                    }
                    if (AptCnt > 0)
                    {
                        await this.AddExistedAsync(appointmentId, isAdmission ? addRecords.PatientId : appRecord.PatientId, isAdmission);
                    }
                    // result.AppointmentId = isAdmission ? addRecords.AdmissionId : appRecord.AppointmentId;
                }
                else
                {
                    query = isAdmission ? $@"select * from ""PediatricEncounter"" pe
                        left join ""CommonEncounter"" CE on CE.""PatientId""=pe.""PatientId""
                        where pe.""PatientId""={addRecords.PatientId}  and  pe.""AdmissionId""={addRecords.AdmissionId} order by 1 desc " :
                    $@"select * from ""PediatricEncounter"" pe
                        left join ""CommonEncounter"" CE on CE.""PatientId""=pe.""PatientId""
                        where pe.""PatientId""={appRecord.PatientId}  and  pe.""AppointmentId""={appRecord.AppointmentId} order by 1 desc ";
                    result = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PediatricEncounterModel>(query);
                }

            }
            return result;


        }


        public async Task<CommonResponse> AddExistedAsync(int appointmentId, int patientId, bool isAdmission)
        {
            var count = 0;
            var commonResponse = new CommonResponse { Status = 1 };
            var records = new PediatricEncounterModel();
            var admissionRecords = new Admission();
            var appointmentRecords = new Appointment();
            var query = $@"select * from ""PediatricEncounter"" where ""PatientId""={patientId} order by 1 desc ";
            records = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PediatricEncounterModel>(query);
            if (isAdmission)
            {
                admissionRecords = this.unitOfWork.Admission.Find(s => s.AdmissionId == appointmentId);

            }
            else
            {
                appointmentRecords = this.unitOfWork.Appointments.Find(s => s.AppointmentId == appointmentId);
            }
            var ancQuerry = $@"select * from ""PediatricEncounter"" where ""PatientId""={patientId} and ""Active""=true order by 1 desc ";
            var ancCardRecords = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PediatricEncounter>(query);
            var ancRecords = new PediatricEncounter();
            var ancCardQuerry = isAdmission ? $@"select * from ""PediatricEncounter"" where ""PatientId""={patientId}  order by 1 desc " :
                $@"select * from ""PediatricEncounter"" where ""PatientId""={patientId}   order by 1 desc ";
            ancRecords = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PediatricEncounter>(ancCardQuerry);

            var encounter = new PediatricEncounter
            {
                Active = true,
                AdmissionId = admissionRecords.AdmissionId,
                AppointmentId = appointmentRecords.AppointmentId,
                CreatedDate = DateTime.UtcNow,
                PatientId = isAdmission ? admissionRecords.PatientId : appointmentRecords.PatientId,
            };
            if (records != null)
            {
                
                {
                    encounter.Measurements = records.Measurements;
                    encounter.DownSyndromeFollowUp= records.DownSyndromeFollowUp;
                    encounter.HighRiskIntial = records.HighRiskIntial;
                    encounter.SpecialFeatures = records.SpecialFeatures;
                    encounter.Syndrome = records.Syndrome;
                    encounter.PediatricRisk = records.PediatricRisk;
                    encounter.NeonatalRisk = records.NeonatalRisk;
                    encounter.Allergies = records.Allergies;
                    encounter.ClinicalExamination = records.ClinicalExamination;
                    encounter.MChat = records.MChat;
                    encounter.VaccineDetail = records.VaccineDetail;
                    encounter.PediatricGuide = records.PediatricGuide;
                    encounter.Reminder = records.Reminder;


                }
            }


            var existedRecords = this.unitOfWork.PediatricEncounters.Find(s => s.AppointmentId == appointmentId);
            count++;
            if (count == 1)
            {
                var response = await this.unitOfWork.PediatricEncounters.InsertAsync(encounter);
                commonResponse.Response = response;
                return commonResponse;
            }

            return commonResponse;

        }
        
        public  Task<PediatricEncounterFullTranscriptModel> 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"",
							""PediatricEncounterId"",P.""UMRNo"", pr.""Email"",L.""Name"" as ""PracticeLocation"",
                             ""Measurements"",""NeonatalRisk"",""PediatricRisk"",""Syndrome"",""ClinicalExamination"",""DownSyndromeFollowUp"",""HighRiskIntial"",""OrderPrescription"",""Allergies"",""MChat"",CE.""FamilyHistory"",CE.""BirthHistory"",""SpecialFeatures"",""DiagnosisOrder"",""NextVisitOrder"",""VaccineDetail"",""PediatricGuide"",""RefferalOrder"",""Reminder""

                            FROM ""Appointment"" A
							LEFT JOIN ""PediatricEncounter"" ob ON A.""AppointmentId""= ob.""AppointmentId""
							LEFT JOIN ""AppointmentSymptom"" ATS ON  ATS.""AppointmentId"" = A.""AppointmentId""
                            LEFT JOIN ""CommonEncounter"" CE ON  CE.""PatientId"" = A.""PatientId""
                            LEFT JOIN ""Provider"" pr on pr.""ProviderId""=A.""ProviderId""
							JOIN ""Patient"" P ON P.""PatientId"" = A.""PatientId""
                            LEFT JOIN ""Location"" L on L.""LocationId""=A.""LocationId""
                            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<PediatricEncounterFullTranscriptModel>(query);
        }

        public async Task<int> FetchVisitNoAsync(int patientId)
        {
            var query = $@"select count(*) from ""PediatricEncounter"" where ""PatientId""={patientId} and  ""Active""=true";
          
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);


        }

        /// <inheritdoc />
        public async Task<IEnumerable<PediatricMeasurmentModel>> FetchPediatricMeasurementHistoryAsync(int patientId)
        {
            var query = $@"select pe.""CreatedDate"" ,pe.""Measurements"" , pe.""CreatedBy"", a2.""FullName"" as ""CreatedByName""
	                        from public.""PediatricEncounter"" pe 
 	                        join public.""Appointment"" a on a.""AppointmentId"" = pe.""AppointmentId"" and a.""Active"" is true
 	                        join public.""Account"" a2 on a2.""AccountId"" = pe.""CreatedBy"" 
 	                        where pe.""Measurements"" is not null and a.""PatientId"" = {patientId} order by pe.""CreatedDate"" asc";

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

