using Hims.Domain.Repositories.UnitOfWork;
using System;
using System.Collections.Generic;
using System.Text;
using Hims.Domain.Configurations;
using Hims.Domain.Entities;

using Hims.Domain.Services;
using Hims.Shared.Library.Enums;
using Hims.Shared.Library.Helpers;
using Hims.Shared.UserModels.DietEncounter;
using System.Threading.Tasks;
using Hims.Shared.EntityModels;
using Dapper;
using Newtonsoft.Json;
using Hims.Shared.UserModels;

namespace Hims.Infrastructure.Services
{


    public class DietEncounterService : IDietEncounterService
    {
        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="IGynEncounterService"/>
        public DietEncounterService(ITimelineService timelineService, IUnitOfWork unitOfWork, IAmazonS3Configuration amazonS3Configuration)
        {
            this.unitOfWork = unitOfWork;
            this.amazonS3Configuration = amazonS3Configuration;
            this.timelineService = timelineService;
        }

        public async Task<CommonResponse> AddAsync(InsertModel model)
        {
            var commonResponse = new CommonResponse { Status = 1 };
            var checkIf = model.IsAdmission
                ? await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""DietEncounterId"") FROM ""DietEncounter"" WHERE ""AdmissionId"" = {model.AppointmentId}")
                : await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""DietEncounterId"") FROM ""DietEncounter"" 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 DietEncounter
            {
                Active = true,
                AppointmentId = model.IsAdmission ? null : (int?)model.AppointmentId,
                AdmissionId = model.IsAdmission ? (int?)model.AppointmentId : null,
                DietEcounterDate = DateTime.Now,
                CreatedBy = model.ModifiedBy,
                CreatedDate = DateTime.Now,
                PatientId = model.IsAdmission ? admission.PatientId : appointment.PatientId
            };

            switch (model.Type)
            {
                case DietEncounterType.DietPlanPrescribed:
                    encounter.DietPlanPrescribed = model.JsonString;
                    break;
                case DietEncounterType.IpNutritionalScreeningForm:
                    encounter.IpNutritionalScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.OpNutritionScreeningForm:
                    encounter.OpNutritionScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.PediatricCDCScreeningForm:
                    encounter.PediatricCDCScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.SyndromesFormP:
                    encounter.SyndromesFormP = model.JsonString;
                    break;
                case DietEncounterType.OpNutritionalAssessmentForm:
                    encounter.OpNutritionalAssessmentForm = model.JsonString;
                    break;
                case DietEncounterType.DietGuideLines:
                    encounter.DietGuideLines = model.JsonString;
                    break;
                case DietEncounterType.OrderPrescription:
                    encounter.DietGuideLines = model.JsonString;
                    break;
                case DietEncounterType.ReferralForm:
                    encounter.ReferralForm = model.JsonString;
                    break;
                case DietEncounterType.SpecialFeature:
                    encounter.SpecialFeature = model.JsonString;
                    break;

            }
            if (model.Type == DietEncounterType.ReferralForm)
            {

                var value = JsonConvert.DeserializeObject<ReferralFormModel>(model.JsonString);
                value.AppointmentId = model.AppointmentId;
                await this.InsertReferralForm(value);
            }
            var response = await this.unitOfWork.DietEncounter.InsertAsync(encounter);
            commonResponse.Response = response;
            return commonResponse;

        }


        /// <inheritdoc />
        public Task<DietEncounterModel> FindAsync(int appointmentId, bool isAdmission)
        {
            var query = isAdmission
                ? $@"SELECT A.""AdmissionId"" ""AppointmentId"", A.""PatientId"",dt.""SpecialFeature"",dt.""DietEncounterId"",dt.""DietPlanPrescribed"",dt.""OpNutritionalAssessmentForm"",dt.""IpNutritionalScreeningForm"",dt.""OpNutritionScreeningForm"",
                                dt.""PediatricCDCScreeningForm"", dt.""SyndromesFormP"",dt.""DietGuideLines""                 
                                FROM ""Admission"" A
                           LEFT JOIN ""DietEncounter"" dt ON dt.""AppointmentId"" = A.""AppointmentId""
                            where A.""AdmissionId"" = '{appointmentId}' AND A.""Active"" IS TRUE"
                : $@"SELECT A.""AppointmentId"", A.""PatientId"", dt.""DietEncounterId"",dt.""SpecialFeature"",dt.""DietPlanPrescribed"",dt.""OpNutritionalAssessmentForm"",dt.""IpNutritionalScreeningForm"",dt.""OpNutritionScreeningForm"",dt.""OrderPrescription"",
                                dt.""PediatricCDCScreeningForm"",dt. ""SyndromesFormP"",dt.""DietGuideLines"",dt.""ReferralForm""
                            FROM ""Appointment"" A
                            LEFT JOIN ""DietEncounter"" dt ON dt.""AppointmentId"" = A.""AppointmentId""
                            where A.""AppointmentId"" = '{appointmentId}' AND A.""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<DietEncounterModel>(query);
        }

        public async Task<CommonResponse> UpdateAsync(InsertModel model)
        {
            var commonResponse = new CommonResponse { Status = 1 };
            var encounter = await this.unitOfWork.DietEncounter.FindAsync(m => m.DietEncounterId == model.DietEncounterId);

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

            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);
            }
            encounter.ModifiedBy = model.ModifiedBy;
            encounter.ModifiedDate = DateTime.Now;
            encounter.PatientId = model.IsAdmission ? admission.PatientId : appointment.PatientId;
            switch (model.Type)
            {
                case DietEncounterType.DietPlanPrescribed:
                    encounter.DietPlanPrescribed = model.JsonString;
                    break;
                case DietEncounterType.IpNutritionalScreeningForm:
                    encounter.IpNutritionalScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.OpNutritionScreeningForm:
                    encounter.OpNutritionScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.PediatricCDCScreeningForm:
                    encounter.PediatricCDCScreeningForm = model.JsonString;
                    break;
                case DietEncounterType.SyndromesFormP:
                    encounter.SyndromesFormP = model.JsonString;
                    break;
                case DietEncounterType.OpNutritionalAssessmentForm:
                    encounter.OpNutritionalAssessmentForm = model.JsonString;
                    break;
                case DietEncounterType.DietGuideLines:
                    encounter.DietGuideLines = model.JsonString;
                    break;
                case DietEncounterType.OrderPrescription:
                    encounter.OrderPrescription = model.JsonString;
                    break;
                case DietEncounterType.ReferralForm:
                    encounter.ReferralForm = model.JsonString;
                    break;
                case DietEncounterType.SpecialFeature:
                    encounter.SpecialFeature = model.JsonString;
                    break;
            }
            if (model.Type == DietEncounterType.ReferralForm)
            {

                var value = JsonConvert.DeserializeObject<ReferralFormModel>(model.JsonString);
                value.AppointmentId = model.AppointmentId;
                await this.InsertReferralForm(value);
            }
            var updated = await this.unitOfWork.DietEncounter.UpdateAsync(encounter);
            commonResponse.Response = updated > 0 ? encounter.DietEncounterId : 0;
            return commonResponse;
        }

        public async Task<int> InsertReferralForm(ReferralFormModel model)
        {

            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>($@"select count(*) from ""ReferralForm"" where  ""AppointmentId""= '{model.AppointmentId}'");
            var referralForm = new ReferralForm();
            referralForm.ReferralDoctor = model.ReferralDoctor;
            referralForm.Reason = model.Reason;
            referralForm.RequiredDate = model.RequiredDate;
            referralForm.Time = model.Time;
            referralForm.ConsultantDoctor = model.ConsultantDoctor;
            referralForm.AppointmentId = (int)model.AppointmentId;
            referralForm.CreatedDate = DateTime.Now;
            referralForm.Active = model.Active;
            referralForm.ProviderId = model.ProviderId;
            referralForm.ProviderId = model.ProviderId;
            referralForm.PatientId = model.PatientId;
            referralForm.Opinion = model.Opinion;
            if (checkIf > 0)
            {
                var records = this.unitOfWork.ReferralForms.Find(s => s.AppointmentId == model.AppointmentId);
                referralForm.ReferralFormId = records.ReferralFormId;
                return await this.unitOfWork.ReferralForms.UpdateAsync(referralForm);
            }

            return await this.unitOfWork.ReferralForms.InsertAsync(referralForm);


        }
        public async Task<DietEncounterResource> FindDashboardAsync(int appointmentId, DietEncounterType type, bool isAdmission)
        {

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

            var dietEncounterResource = new DietEncounterResource
            {
                AppointmentId = appointmentId,
                DietEncounterId = null,
                JsonString = null
            };

            if (dietEncounter != null)
            {
                dietEncounterResource.DietEncounterId = dietEncounter.DietEncounterId;
                switch (type)
                {
                    case DietEncounterType.DietPlanPrescribed:
                        dietEncounterResource.JsonString = dietEncounter.DietPlanPrescribed;
                        break;
                    case DietEncounterType.OpNutritionScreeningForm:
                        dietEncounterResource.JsonString = dietEncounter.OpNutritionScreeningForm;
                        break;
                    case DietEncounterType.PediatricCDCScreeningForm:
                        dietEncounterResource.JsonString = dietEncounter.PediatricCDCScreeningForm;
                        break;
                    case DietEncounterType.IpNutritionalScreeningForm:
                        dietEncounterResource.JsonString = dietEncounter.IpNutritionalScreeningForm;
                        break;
                    case DietEncounterType.SyndromesFormP:
                        dietEncounterResource.JsonString = dietEncounter.SyndromesFormP;
                        break;
                    case DietEncounterType.OpNutritionalAssessmentForm:
                        dietEncounterResource.JsonString = dietEncounter.OpNutritionalAssessmentForm;
                        break;
                    case DietEncounterType.DietGuideLines:
                        dietEncounterResource.JsonString = dietEncounter.DietGuideLines;
                        break;
                    case DietEncounterType.OrderPrescription:
                        dietEncounterResource.JsonString = dietEncounter.OrderPrescription;
                        break;
                    case DietEncounterType.SpecialFeature:
                        dietEncounterResource.JsonString = dietEncounter.SpecialFeature;
                        break;


                    case DietEncounterType.ReferralForm:
                        dietEncounterResource.JsonString = dietEncounter.ReferralForm;
                        break;
                }
            }

            return dietEncounterResource;


        }
        public async Task<int> FetchVisitNoAsync(int patientId)
        {
            var query = $@"select count(a.""PatientId"") as ""Count""
                    from ""DietEncounter"" de
                    join ""Appointment"" a on a.""AppointmentId"" = de.""AppointmentId""
                    where a.""PatientId"" = {patientId}";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);

        }

        public Task<DietFullTrascriptModel> FindPrescriptionAsync(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"",P.""UMRNo"" as ""PatientNo"",P.""FatherOrHusband"" as ""Partner"",
                            (case when A.""PatientFamilyId"" is not null then PF.""Age"" else P.""Age"" end) AS ""PatientAge"", P.""DateOfBirth"" AS ""PatientDateOfBirth"",dt.*
                            FROM ""Appointment"" A
							LEFT JOIN ""DietEncounter"" dt ON A.""AppointmentId""= dt.""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<DietFullTrascriptModel>(query);
        }
        public async Task<DietFullTrascriptModel> FindGpla(int? appointmentId)
        {
            var where = $@" where d.""AppointmentId""={appointmentId}";
            var query = $@"select d.""PatientId"" from ""Appointment"" d {where}";
            var data = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<DietFullTrascriptModel>(query);
            var whereQuery = $@" where ""PatientId""={data.PatientId}";
            var query1 = $@" select ""GynHistory"",""MeasureCommonData"",""CreatedDate"",""ModifiedDate"" from ""GynEncounter"" {whereQuery}
union all
select ""AncCard"",""MeasureCommonData"",""CreatedDate"",""ModifiedDate""  from ""ObEncounter"" 
{whereQuery}

order by ""ModifiedDate"" desc";

            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<DietFullTrascriptModel>(query1);
        }
    }
}
