namespace Hims.Infrastructure.Services
{
    using System;
    using System.Threading.Tasks;
    using Dapper;
    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.Domain.Configurations;
    using Hims.Shared.Library.Helpers;

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

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

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

        /// <inheritdoc />
        public Task<BehavioralHealthModel> FindAsync(int appointmentId)
        {
            var query = $@"SELECT A.""AppointmentId"", bh.*, ATS.""Symptoms"" FROM ""Appointment"" A
                            LEFT JOIN ""BehavioralHealth"" bh ON bh.""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<BehavioralHealthModel>(query);
        }

        /// <inheritdoc />
        public async Task<BehavioralHealthResource> FindDashboardAsync(int appointmentId, BehavioralHealthType type)
        {
            var behavioral = await this.unitOfWork.BehavioralHealth.FindAsync(m => m.AppointmentId == appointmentId);

            var behavioralResource = new BehavioralHealthResource
            {
                AppointmentId = appointmentId,
                BehavioralHealthId = null,
                JsonString = null
            };

            if (behavioral != null)
            {
                behavioralResource.BehavioralHealthId = behavioral.BehavioralHealthId;
                switch (type)
                {
                    case BehavioralHealthType.ProblemHistory:
                        behavioralResource.JsonString = behavioral.ProblemHistory;
                        break;
                    case BehavioralHealthType.MedicalHistory:
                        behavioralResource.JsonString = behavioral.MedicalHistory;
                        break;
                    case BehavioralHealthType.CurrentSupport:
                        behavioralResource.JsonString = behavioral.CurrentSupport;
                        break;
                    case BehavioralHealthType.CurrentLiving:
                        behavioralResource.JsonString = behavioral.CurrentLiving;
                        break;
                    case BehavioralHealthType.EducationalHistory:
                        behavioralResource.JsonString = behavioral.EducationalHistory;
                        break;
                    case BehavioralHealthType.ClientStrengths:
                        behavioralResource.JsonString = behavioral.ClientStrengths;
                        break;
                    case BehavioralHealthType.OutComeMeasures:
                        behavioralResource.JsonString = behavioral.OutComeMeasures;
                        break;
                    case BehavioralHealthType.SubstanceHistory:
                        behavioralResource.JsonString = behavioral.SubstanceHistory;
                        break;
                    case BehavioralHealthType.WorkHistory:
                        behavioralResource.JsonString = behavioral.WorkHistory;
                        break;
                    case BehavioralHealthType.AbuseHistory:
                        behavioralResource.JsonString = behavioral.AbuseHistory;
                        break;
                    case BehavioralHealthType.ReligionSpirituality:
                        behavioralResource.JsonString = behavioral.ReligionSpirituality;
                        break;
                    case BehavioralHealthType.MentalStatus:
                        behavioralResource.JsonString = behavioral.MentalStatus;
                        break;
                    case BehavioralHealthType.FamilyRelationships:
                        behavioralResource.JsonString = behavioral.FamilyRelationships;
                        break;
                    case BehavioralHealthType.RelapsePredictors:
                        behavioralResource.JsonString = behavioral.RelapsePredictors;
                        break;
                    case BehavioralHealthType.PatientQuestionnaire:
                        behavioralResource.JsonString = behavioral.PatientQuestionnaire;
                        break;
                    case BehavioralHealthType.GeneralisedAnxietyDisorder:
                        behavioralResource.JsonString = behavioral.GeneralisedAnxietyDisorder;
                        break;
                    case BehavioralHealthType.BurnsDepression:
                        behavioralResource.JsonString = behavioral.BurnsDepression;
                        break;
                    case BehavioralHealthType.Aims:
                        behavioralResource.JsonString = behavioral.Aims;
                        break;
                    case BehavioralHealthType.Genogram:
                        behavioralResource.JsonString = behavioral.Genogram;
                        break;
                    case BehavioralHealthType.Notes:
                        behavioralResource.JsonString = behavioral.Notes;
                        break;
                    case BehavioralHealthType.Vitals:
                        behavioralResource.JsonString = behavioral.Vitals;
                        break;
                    case BehavioralHealthType.ReferralProvider:
                        behavioralResource.JsonString = behavioral.ReferralProvider;
                        break;
                    case BehavioralHealthType.FollowUp:
                        behavioralResource.JsonString = behavioral.FollowUp;
                        break;
                    case BehavioralHealthType.Medications:
                        behavioralResource.JsonString = behavioral.Medications;
                        behavioralResource.MedicationComment = behavioral.MedicationComment;
                        break;
                    case BehavioralHealthType.TreatmentPlan:
                        behavioralResource.JsonString = behavioral.TreatmentPlan;
                        break;
                }
            }

            return behavioralResource;
        }

        /// <inheritdoc />
        public async Task<int> UpdateAsync(BehavioralModifyModel model)
        {
            BehavioralHealth behavioral;
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""BehavioralHealthId"") FROM ""BehavioralHealth"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""BehavioralHealthId"" = '{model.BehavioralHealthId}'");
            if (checkIf <= 0)
            {
                behavioral = new BehavioralHealth
                {
                    Active = true,
                    AppointmentId = model.AppointmentId,
                    BehavioralHealthDate = DateTime.UtcNow,
                    CreatedBy = model.ModifiedBy,
                    CreatedDate = DateTime.UtcNow
                };
            }
            else
            {
                behavioral = await this.unitOfWork.BehavioralHealth.FindAsync(m => m.BehavioralHealthId == model.BehavioralHealthId);
                behavioral.ModifiedBy = model.ModifiedBy;
                behavioral.ModifiedDate = DateTime.UtcNow;
            }

            switch (model.Type)
            {
                case BehavioralHealthType.ProblemHistory:
                    behavioral.ProblemHistory = model.JsonString;
                    break;
                case BehavioralHealthType.MedicalHistory:
                    behavioral.MedicalHistory = model.JsonString;
                    break;
                case BehavioralHealthType.CurrentSupport:
                    behavioral.CurrentSupport = model.JsonString;
                    break;
                case BehavioralHealthType.CurrentLiving:
                    behavioral.CurrentLiving = model.JsonString;
                    break;
                case BehavioralHealthType.EducationalHistory:
                    behavioral.EducationalHistory = model.JsonString;
                    break;
                case BehavioralHealthType.ClientStrengths:
                    behavioral.ClientStrengths = model.JsonString;
                    break;
                case BehavioralHealthType.OutComeMeasures:
                    behavioral.OutComeMeasures = model.JsonString;
                    break;
                case BehavioralHealthType.SubstanceHistory:
                    behavioral.SubstanceHistory = model.JsonString;
                    break;
                case BehavioralHealthType.WorkHistory:
                    behavioral.WorkHistory = model.JsonString;
                    break;
                case BehavioralHealthType.AbuseHistory:
                    behavioral.AbuseHistory = model.JsonString;
                    break;
                case BehavioralHealthType.ReligionSpirituality:
                    behavioral.ReligionSpirituality = model.JsonString;
                    break;
                case BehavioralHealthType.MentalStatus:
                    behavioral.MentalStatus = model.JsonString;
                    break;
                case BehavioralHealthType.FamilyRelationships:
                    behavioral.FamilyRelationships = model.JsonString;
                    break;
                case BehavioralHealthType.RelapsePredictors:
                    behavioral.RelapsePredictors = model.JsonString;
                    break;
                case BehavioralHealthType.PatientQuestionnaire:
                    behavioral.PatientQuestionnaire = model.JsonString;
                    break;
                case BehavioralHealthType.GeneralisedAnxietyDisorder:
                    behavioral.GeneralisedAnxietyDisorder = model.JsonString;
                    break;
                case BehavioralHealthType.BurnsDepression:
                    behavioral.BurnsDepression = model.JsonString;
                    break;
                case BehavioralHealthType.Aims:
                    behavioral.Aims = model.JsonString;
                    break;
                case BehavioralHealthType.Genogram:
                    behavioral.Genogram = model.JsonString;
                    break;
                case BehavioralHealthType.Notes:
                    behavioral.Notes = model.JsonString;
                    break;
                case BehavioralHealthType.Vitals:
                    behavioral.Vitals = model.JsonString;
                    break;
                case BehavioralHealthType.ReferralProvider:
                    behavioral.ReferralProvider = model.JsonString;
                    break;
                case BehavioralHealthType.FollowUp:
                    behavioral.FollowUp = model.JsonString;
                    break;
                case BehavioralHealthType.Medications:
                    behavioral.Medications = model.JsonString;
                    break;
                case BehavioralHealthType.TreatmentPlan:
                    behavioral.TreatmentPlan = model.JsonString;
                    break;
                case BehavioralHealthType.MedicationComment:
                    behavioral.MedicationComment = model.JsonString;
                    break;
            }

            if (checkIf <= 0)
            {
                behavioral.BehavioralHealthId = await this.unitOfWork.BehavioralHealth.InsertAsync(behavioral);
                return behavioral.BehavioralHealthId;
            }

            await this.unitOfWork.BehavioralHealth.UpdateAsync(behavioral);
            return behavioral.BehavioralHealthId;
        }

        /// <inheritdoc />
        public async Task<CommonResponse> UpdateAltAsync(BehavioralModifyModel model)
        {
            var response = new CommonResponse { Status = 1 };
            BehavioralHealth behavioral;
            var checkIf = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"SELECT COUNT(""BehavioralHealthId"") FROM ""BehavioralHealth"" WHERE ""AppointmentId"" = '{model.AppointmentId}' AND ""BehavioralHealthId"" = '{model.BehavioralHealthId}'");
            if (checkIf <= 0)
            {
                behavioral = new BehavioralHealth
                {
                    Active = true,
                    AppointmentId = model.AppointmentId,
                    BehavioralHealthDate = DateTime.UtcNow,
                    CreatedBy = model.ModifiedBy,
                    CreatedDate = DateTime.UtcNow
                };
            }
            else
            {
                behavioral = await this.unitOfWork.BehavioralHealth.FindAsync(m => m.BehavioralHealthId == model.BehavioralHealthId);
                behavioral.ModifiedBy = model.ModifiedBy;
                behavioral.ModifiedDate = DateTime.UtcNow;
            }

            switch (model.Type)
            {
                case BehavioralHealthType.ProblemHistory:
                    behavioral.ProblemHistory = model.JsonString;
                    break;
                case BehavioralHealthType.MedicalHistory:
                    behavioral.MedicalHistory = model.JsonString;
                    break;
                case BehavioralHealthType.CurrentSupport:
                    behavioral.CurrentSupport = model.JsonString;
                    break;
                case BehavioralHealthType.CurrentLiving:
                    behavioral.CurrentLiving = model.JsonString;
                    break;
                case BehavioralHealthType.EducationalHistory:
                    behavioral.EducationalHistory = model.JsonString;
                    break;
                case BehavioralHealthType.ClientStrengths:
                    behavioral.ClientStrengths = model.JsonString;
                    break;
                case BehavioralHealthType.OutComeMeasures:
                    behavioral.OutComeMeasures = model.JsonString;
                    break;
                case BehavioralHealthType.SubstanceHistory:
                    behavioral.SubstanceHistory = model.JsonString;
                    break;
                case BehavioralHealthType.WorkHistory:
                    behavioral.WorkHistory = model.JsonString;
                    break;
                case BehavioralHealthType.AbuseHistory:
                    behavioral.AbuseHistory = model.JsonString;
                    break;
                case BehavioralHealthType.ReligionSpirituality:
                    behavioral.ReligionSpirituality = model.JsonString;
                    break;
                case BehavioralHealthType.MentalStatus:
                    behavioral.MentalStatus = model.JsonString;
                    break;
                case BehavioralHealthType.FamilyRelationships:
                    behavioral.FamilyRelationships = model.JsonString;
                    break;
                case BehavioralHealthType.RelapsePredictors:
                    behavioral.RelapsePredictors = model.JsonString;
                    break;
                case BehavioralHealthType.PatientQuestionnaire:
                    behavioral.PatientQuestionnaire = model.JsonString;
                    break;
                case BehavioralHealthType.GeneralisedAnxietyDisorder:
                    behavioral.GeneralisedAnxietyDisorder = model.JsonString;
                    break;
                case BehavioralHealthType.BurnsDepression:
                    behavioral.BurnsDepression = model.JsonString;
                    break;
                case BehavioralHealthType.Aims:
                    behavioral.Aims = model.JsonString;
                    break;
                case BehavioralHealthType.Genogram:
                    behavioral.Genogram = model.JsonString;
                    break;
                case BehavioralHealthType.Notes:
                    behavioral.Notes = model.JsonString;
                    break;
                case BehavioralHealthType.Vitals:
                    behavioral.Vitals = model.JsonString;
                    break;
                case BehavioralHealthType.ReferralProvider:
                    behavioral.ReferralProvider = model.JsonString;
                    break;
                case BehavioralHealthType.FollowUp:
                    behavioral.FollowUp = model.JsonString;
                    break;
                case BehavioralHealthType.Medications:
                    behavioral.Medications = model.JsonString;
                    response.Status = 2;
                    break;
                case BehavioralHealthType.TreatmentPlan:
                    behavioral.TreatmentPlan = model.JsonString;
                    break;
                case BehavioralHealthType.MedicationComment:
                    behavioral.MedicationComment = model.JsonString;
                    break;
            }

            if (checkIf <= 0)
            {
                behavioral.BehavioralHealthId = await this.unitOfWork.BehavioralHealth.InsertAsync(behavioral);
                response.Response = behavioral.BehavioralHealthId;
                return response;
            }

            await this.unitOfWork.BehavioralHealth.UpdateAsync(behavioral);
            response.Response = behavioral.BehavioralHealthId;
            return response;
        }

        /// <inheritdoc />
        public Task<BehavioralPrescriptionModel> FindPrescriptionAsync(int appointmentId)
        {
            var query = $@"SELECT A.""AppointmentId"",A.""AppointmentNo"",A.""AppointmentDate"",A.""AppointmentTime"", bh.""BehavioralHealthId"", bh.""Medications"", bh.""FollowUp"", bh.""MedicationComment"",
							CONCAT(Pr.""Salutation"",' ', Pr.""FullName"") AS ""ProviderName"",Pr.""ProviderNo"",S.""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"",CONCAT('(+', ct.""CountryCode"", ') ', pt.""Mobile"") AS ""PatientMobile"" FROM ""Appointment"" A
							JOIN ""BehavioralHealth"" bh ON bh.""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.""ProviderId"" =Pr.""ProviderId""
							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""
							JOIN ""Country"" ct ON ct.""CountryId""=pt.""CountryId""
                            where bh.""AppointmentId"" = {appointmentId} AND bh.""Active"" IS TRUE";
            return this.unitOfWork.Current.QueryFirstOrDefaultAsync<BehavioralPrescriptionModel>(query);
        }

        /// <inheritdoc />
        public Task<BehavioralHealthFullTranscriptModel> 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"",
                            CONCAT(Pr.""Salutation"",' ', Pr.""FullName"") AS ""ProviderName"",
							(CASE WHEN P.""ThumbnailUrl"" IS NOT NULL THEN CONCAT('{this.amazonS3Configuration.BucketURL}', P.""Guid"", '/', P.""ThumbnailUrl"") ELSE NULL END) AS ""PatientThumbnailUrl"",
                            ""BehavioralHealthId"",""ProblemHistory"",""MedicalHistory"",""CurrentSupport"",""CurrentLiving"",""EducationalHistory"",
							""ClientStrengths"",""OutComeMeasures"",""SubstanceHistory"",""WorkHistory"",""AbuseHistory"",""ReligionSpirituality"",
							""MentalStatus"",""FamilyRelationships"",""RelapsePredictors"",""PatientQuestionnaire"",""GeneralisedAnxietyDisorder"",
							""BurnsDepression"",""Aims"",""Genogram"",""Notes"",""Vitals"",""ReferralProvider"",""FollowUp"",""Medications"",""TreatmentPlan"", ""MedicationComment"",
                            ATS.""Symptoms"" FROM ""Appointment"" A
							LEFT JOIN ""BehavioralHealth"" hm ON A.""AppointmentId""= hm.""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<BehavioralHealthFullTranscriptModel>(query);
        }
    }
}
