using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Pluto.Api;
using McKesson.PPS.Fusion.Authentication.Business;
using McKesson.PPS.Fusion.MedsAllergies.Business;
using McKesson.PPS.Fusion.ProblemsProcedures.Business;
using McKesson.PPS.Fusion.OrderEntry.Business;
using McKesson.PPS.Fusion.Labs.Business;
using McKesson.PPS.Fusion.PatientBanner.Business;
using McKesson.PPS.Fusion.Persons.Business;
using McKesson.PPS.Fusion.VitalSigns.Business;
using McKesson.PPS.Fusion.ProgressNotes.Business;

namespace PlutoServer.PracticeChoice.Core {
    public class Patient {
        public ChartInfo1 GetChart(string authToken, int patientId, int chartId) {
            ChartInfo1 chartInfo = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;

                chartInfo = new ChartInfo1();
                chartInfo.Patient = new PatientInfo1();

                var personInfo = McKesson.PPS.Fusion.Persons.Business.PersonInfo.GetPersonInfo(new PersonInfoCriteria() { PersonID = patientId });
                if(personInfo != null) {
                    chartInfo.Patient.ChartId = chartId;
                    chartInfo.Patient.DOB = personInfo.DateOfBirth.Value;
                    chartInfo.Patient.FirstName = personInfo.FirstName;
                    chartInfo.Patient.Id = personInfo.Id;
                    chartInfo.Patient.LastName = personInfo.LastName;
                    chartInfo.Patient.PrimaryAddress = new AddressInfo1() { 
                        Address1 = personInfo.PersonAddress.Address1,
                        Address2 = personInfo.PersonAddress.Address2,
                        City = personInfo.PersonAddress.City,
                        Country = personInfo.PersonAddress.Country.Value,
                        State = personInfo.PersonAddress.State.Value,
                        Zip = personInfo.PersonAddress.Zip
                    };
                    chartInfo.Patient.PrimaryPhone = this.GetDefaultPhoneNumber(personInfo);
                }

                var piCriteria = new PatientInfoCriteria() { ChartID = chartId };
                var pi = PatientInfo.GetPatientInfo(piCriteria);
                if(pi != null) {
                    chartInfo.Patient.Age = pi.Age;
                    chartInfo.Patient.ChartId = chartId;
                    chartInfo.Patient.Gender = pi.Gender;
                    chartInfo.Patient.Weight = pi.Weight;
                }

                var problems = this.GetPatientProblems(chartId);
                if(problems != null) {
                    chartInfo.Problems = problems.ToArray();
                }

                var meds = this.GetPatientMeds(chartId);
                if(meds != null) {
                    chartInfo.Medications = meds.ToArray();
                }

                var allergies = this.GetPatientAllergies(chartId);
                if(allergies != null) {
                    chartInfo.Allergies = allergies.ToArray();
                }

                var orders = this.GetPatientOrders(chartId);
                if(orders != null) {
                    chartInfo.Orders = orders.ToArray();
                }

                var results = this.GetPatientResults(chartId, 1, 5);
                if(results != null) {
                    chartInfo.Results = results.ToArray();
                }

                var vitalSigns = this.GetPatientVitalSigns(chartId, patientId);
                if(vitalSigns != null) {
                    chartInfo.VitalSigns = vitalSigns.ToArray();
                }

                var notes = this.GetPatientNotes(patientId, chartId);
                if(notes != null) {
                    chartInfo.Notes = notes.ToArray();
                }
            }
            return chartInfo;
        }

        private string GetDefaultPhoneNumber(McKesson.PPS.Fusion.Persons.Business.PersonInfo personInfo) {
            var phoneNbr = string.Empty;
            if(!string.IsNullOrEmpty(personInfo.PhoneEvening)){
                phoneNbr = personInfo.PhoneEvening;
            }else if(!string.IsNullOrEmpty(personInfo.PhoneDayTime)){
                phoneNbr = personInfo.PhoneDayTime;
            } else if (!string.IsNullOrEmpty(personInfo.PhoneCell)){
                phoneNbr = personInfo.PhoneCell;
            }
            return phoneNbr;
        }

        public IList<PrescribedMedicationInfo1> GetMedications(string authToken, int chartId) {
            IList<PrescribedMedicationInfo1> medsList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                medsList = this.GetPatientMeds(chartId);
            }
            return medsList;
        }

        private IList<PrescribedMedicationInfo1> GetPatientMeds(int chartId) {
            IList<PrescribedMedicationInfo1> medsList = null;
            var criteria = new MedsFetchByChartIDCriteria(chartId);
            var meds = MedicationList.GetMedicationList(criteria);
            if(meds != null) {
                medsList = new List<PrescribedMedicationInfo1>();
                foreach(var med in meds) {
                    medsList.Add(new PrescribedMedicationInfo1() {
                        Id = med.MedicationId,
                        IsActive = med.IsActive,
                        Mode = med.Mode,
                        Name = med.MedicationName,
                        NumberOfRefills = med.Refills,
                        PharmacyAddress = med.PharmacyAddress,
                        PharmacyFax = med.PharmacyFax,
                        PharmacyName = med.PharmacyName,
                        PharmacyPhone = med.PharmacyPhone,
                        ProviderId = med.ProviderId,
                        ProviderName = med.ProviderName,
                        Quantity = med.Quantity,
                        SIG = med.SIG,
                        StartDate = med.StartDate,
                        Status = med.Status.Value,
                        StopDate = med.StartDate,
                        Unit = med.Unit
                    });
                }
            }
            return medsList;
        }

        public IList<AllergyInfo1> GetAllergies(string authToken, int chartId) {
            IList<AllergyInfo1> allergyList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                allergyList = this.GetPatientAllergies(chartId);
            }
            return allergyList;
        }

        private IList<AllergyInfo1> GetPatientAllergies(int chartId) {
            IList<AllergyInfo1> allergyList = null;
            var allergies = AllergyInfoList.GetAllergyList(chartId);
            if(allergies != null) {
                allergyList = new List<AllergyInfo1>();
                foreach(var allergy in allergies) {
                    allergyList.Add(new AllergyInfo1() {
                        EndDate = allergy.EndDate.HasValue ? allergy.EndDate.Value : DateTime.MinValue,
                        Id = allergy.AllergyID,
                        IsActive = allergy.IsActive,
                        Name = allergy.AllergyName,
                        Reaction = allergy.AllergyReactionName,
                        Severity = allergy.AllergySeverityName,
                        StartDate = allergy.StartDate.HasValue ? allergy.StartDate.Value : DateTime.MinValue,
                        Type = allergy.AllergyTypeName
                    });
                }
            }
            return allergyList;
        }

        public IList<ProblemInfo1> GetProblems(string authToken, int chartId) {
            IList<ProblemInfo1> problemList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                problemList = this.GetPatientProblems(chartId);
            }
            return problemList;
        }

        private IList<ProblemInfo1> GetPatientProblems(int chartId) {
            IList<ProblemInfo1> problemList = null;
            var problems = DiagnosisInfoList.GetDiagnosisList(new Csla.SingleCriteria<DiagnosisInfoList, int>(chartId));
            if(problems != null) {
                problemList = new List<ProblemInfo1>();
                foreach(var problem in problems) {
                    problemList.Add(new ProblemInfo1() {
                        ActiveDate = problem.ActiveDT,
                        Code = problem.DiagnosisCode,
                        Description = problem.DiagnosisDescription,
                        Id = problem.Id,
                        InActiveDate = problem.InactiveDT,
                        Relevance = problem.RelevanceText,
                        ResolvedDate = problem.ResolvedDate.HasValue ? problem.ResolvedDate.Value : DateTime.MinValue,
                        Status = problem.StatusDescription,
                        Type = problem.DiagnosisTypeName
                    });

                }
            }
            return problemList;
        }

        public IList<ProcedureInfo1> GetProcedures(string authToken, int chartId) {
            IList<ProcedureInfo1> procedureList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                var procedures = ProcedureList.GetProcedureList(new Csla.SingleCriteria<ProcedureList, int>(chartId));
                if(procedures != null) {
                    procedureList = new List<ProcedureInfo1>();
                    foreach(var procedure in procedures) {
                        procedureList.Add(new ProcedureInfo1() {
                            Code = procedure.ProcedureCode,
                            Description = procedure.ProcedureDescription,
                            Id = procedure.ProcedureId,
                            IsPerformedElsewhere = procedure.PerformedElsewhere,
                            Modifier1 = procedure.Modifier1,
                            Modifier2 = procedure.Modifier2,
                            Modifier3 = procedure.Modifier3,
                            Modifier4 = procedure.Modifier4
                        });
                    }
                }
            }
            return procedureList;
        }

        private IList<OrderInfo1> GetPatientOrders(int chartId) {
            IList<OrderInfo1> orderList = null;
            var criteria = new McKesson.PPS.Fusion.OrderEntry.Business.ReadOnlyPatientOrderListCriteria() {
                ChartId = chartId,
                PageIndex = -1, // to compensate for stupid code in PracticeChoice OrderDal.cs CreateGetPatientOrdersCommand
                PageSize = 5
            };
            var orders = McKesson.PPS.Fusion.OrderEntry.Business.ReadOnlyPatientOrderList.GetReadOnlyPatientOrderList(criteria);
            if(orders != null) {
                orderList = new List<OrderInfo1>();
                foreach(var order in orders) {
                    orderList.Add(new OrderInfo1() { 
                        CompletedDate = order.DateCompleted,
                        HasLabs = order.HasLab,
                        Id = order.PatientOrderId,
                        Name = order.OrderName,
                        OrderDate = order.OrderDate,
                        ProviderName = order.ProviderName,
                        Status = order.OrderStatus.Value,
                        Type = order.OrderTypeName
                    });
                }
            }
            return orderList;
        }

        public IList<ResultInfo1> GetResults(string authToken, int chartId, int pageIndex, int pageSize) {
            IList<ResultInfo1> resultList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                resultList = this.GetPatientResults(chartId, pageIndex, pageSize);
            }
            return resultList;
        }

        public IList<VitalSignInfo1> GetVitalSigns(string authToken, int chartId, int patientId) {
            IList<VitalSignInfo1> vsList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                vsList = this.GetPatientVitalSigns(chartId, patientId);
            }
            return vsList;
        }

        public IList<PatientNoteInfo1> GetNotes(string authToken, int patientId, int chartId) {
            IList<PatientNoteInfo1> notesList = null;
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);

                Csla.ApplicationContext.User = principal;
                notesList = this.GetPatientNotes(patientId, chartId);
            }
            return notesList;
        }

        private IList<ResultInfo1> GetPatientResults(int chartId, int pageIndex, int pageSize) {
            IList<ResultInfo1> resultList = null;
            var criteria = new LabResultCriteria() {
                ChartId = chartId,
                PageIndex = pageIndex,
                PageSize = pageSize
            };
            var results = LabResultsOBRList.GetLabResultList(criteria);
            if(results != null) {
                resultList = new List<ResultInfo1>();
                foreach(var result in results) {
                    result.LabResultsOBXes = LabEntryList.GetLabEntryList(result.LabResultsOBRId);
                    var resultDetails = this.GetResultDetails(result);
                    resultList.Add(new ResultInfo1() {
                        CodingSystem = result.ObservationCodingSystem,
                        DateReviewed = result.DateReviewed.HasValue ? result.DateReviewed.Value : DateTime.MinValue,
                        DateSigned = result.DateSigned.HasValue ? result.DateSigned.Value : DateTime.MinValue,
                        Id = result.LabResultsOBRId,
                        IsReviewed = result.IsReviewed,
                        IsSigned = result.IsSigned,
                        Note = result.Note,
                        OrderedBy = result.OrderedBy,
                        PerformingCenter = new PerformingCenterInfo1() { },
                        ResultDate = result.Date,
                        ResultDetails = resultDetails == null? null : resultDetails.ToArray(),
                        Status = result.LabStatusName,
                        TestId = result.ObservationBatteryId,
                        TestName = result.ObservationBatteryText,
                        Type = result.LabTypeName
                    });
                }
            }
            return resultList;
        }

        private IList<ResultDetailInfo1> GetResultDetails(LabResultsOBR result) {
            IList<ResultDetailInfo1> resultDetailsList = null;
            if(result.LabResultsOBXes != null) {
                resultDetailsList = new List<ResultDetailInfo1>();
                foreach(var obx in result.LabResultsOBXes) {
                    resultDetailsList.Add(new ResultDetailInfo1() { 
                        AbnormalFlag = obx.AbnormalFlag,
                        CodingSystem = obx.ObservationCodingSystem,
                        Id = obx.LabResultsOBXId.HasValue?obx.LabResultsOBXId.Value:0,
                        Note = obx.Note,
                        ObservationDate = obx.ObservationDateTime.HasValue?obx.ObservationDateTime.Value:DateTime.MinValue,
                        ObservationId = obx.ObservationIdentifier,
                        ObservationText = obx.ObservationText,
                        ObservationValue = obx.ObservationValue,
                        ReferenceRange = obx.ReferenceRange,
                        Sequence = obx.OBXSequenceNumber,
                        Status = obx.LabResultsStatusName,
                        Units = obx.ObservationUnits
                    });
                }
            }
            return resultDetailsList;
        }

        private IList<VitalSignInfo1> GetPatientVitalSigns(int chartId, int patientId) {
            IList<VitalSignInfo1> vitalSignsList = null;
            bool isMetricMode = false;
            var vitalSigns = VitalSignsList.GetVitalSignsList(new VitalSignCriteria(chartId, null, isMetricMode));
            if(vitalSigns != null) {
                vitalSignsList = new List<VitalSignInfo1>();
                foreach(var vs in vitalSigns) {
                    vitalSignsList.Add(new VitalSignInfo1() {
                        BMI = vs.BMI.HasValue?vs.BMI.Value:0,
                        BPCuffSize = vs.BPCuffSize == null?string.Empty: vs.BPCuffSize.Value,
                        BPSite = vs.BPSiteOfMeasurementType == null? string.Empty:vs.BPSiteOfMeasurementType.Value,
                        Comment = vs.Comment,
                        Diastolic = vs.Diastolic.HasValue?vs.Diastolic.Value:0,
                        EncounterDate = vs.EncounterDate.HasValue? vs.EncounterDate.Value:DateTime.MinValue,
                        ExamDate = vs.ExamDate.HasValue? vs.ExamDate.Value:DateTime.MinValue,
                        HeadCircumference = vs.HeadCircumferenceString,
                        HeadCircumferenceEnglish = string.Empty,
                        Height = vs.HeightString,
                        HeightEnglish = string.Empty,
                        Id = vs.Id,
                        IsMetricMode = vs.IsMetricMode,
                        O2Saturation = vs.O2Liters.HasValue?vs.O2Liters.Value:0,
                        Oximetry = vs.Oximetry.HasValue?vs.Oximetry.Value:0,
                        OxymetrySource = vs.OximetrySourceType == null? string.Empty:vs.OximetrySourceType.Value,
                        PainLevel = vs.PainLevel.HasValue?vs.PainLevel.Value:0,
                        PluseRhythmType = vs.PulseRhythmType == null? string.Empty:vs.PulseRhythmType.Value,
                        PosturalLaying = vs.PosturalLying,
                        PosturalSitting = vs.PosturalSitting,
                        PosturalStanding = vs.PosturalStanding,
                        PostureType = vs.PostureType == null? string.Empty:vs.PostureType.Value,
                        PulseRate = vs.PulseRate.HasValue?vs.PulseRate.Value:0,
                        PulseSite = vs.PulseSiteOfMeasurementType == null? string.Empty:vs.PulseSiteOfMeasurementType.Value,
                        PulseVolumeType = vs.PulseVolumeType == null? string.Empty:vs.PulseVolumeType.Value,
                        RespirationRhythmType = vs.RespirationRhythmType == null? string.Empty:vs.RespirationRhythmType.Value,
                        Respirations = vs.Respirations.HasValue?vs.Respirations.Value:0,
                        RespirationsDepth = vs.RespirationsDepthType == null? string.Empty:vs.RespirationsDepthType.Value,
                        Systolic = vs.Systolic.HasValue?vs.Systolic.Value:0,
                        Temperature = vs.TemperatureString,
                        TemperatureEnglish = vs.TemperatureEnglishString,
                        TemperatureSite = vs.TemperatureSiteOfMeasurementType == null? string.Empty:vs.TemperatureSiteOfMeasurementType.Value,
                        Weight = vs.WeightString,
                        WeightEnglish = vs.WeightEnglishString
                    });
                }
            }
            return vitalSignsList;
        }

        private IList<PatientNoteInfo1> GetPatientNotes(int patientId, int chartId) {
            IList<PatientNoteInfo1> notesList = null;
            var notes = ProgressNoteList.GetProgressNoteList(new ProgressNoteSearchCriteria() { 
                ChartId = chartId
            });
            if(notes != null) {
                notesList = new List<PatientNoteInfo1>();
                notesList = (from note in notes
                            where note.NoteTypeId == 3
                            select new PatientNoteInfo1(){
                                ChartId = chartId,
                                Id = note.NoteId,
                                NoteText = note.NoteOriginalText,
                                Status = note.NoteStatusName,
                                Title = note.NoteTitle,
                                Type = note.NoteTypeName
                            }).ToList<PatientNoteInfo1>();
            }
            return notesList;
        }

        public void AddPatientNote(string authToken, int patientId, int chartId, PatientNoteInfo1 patientNote) {
            MagicIdentity identity = MagicIdentity.FromCookieString(authToken);
            if(identity.IsAuthenticated) {
                MagicPrincipal principal = new MagicPrincipal(identity);
                Csla.ApplicationContext.User = principal;

                var newNote = EditableProgressNote.NewProgressNote();
                newNote.NoteTitle = patientNote.Title;
                newNote.NoteText = GetClinicalNote(patientNote.NoteText);
                //TODO: Remove these hard coding. Phulease
                newNote.NoteStatusId = McKesson.PPS.Fusion.ProgressNotes.Shared.NoteStatusEnum.SAVE;
                newNote.NoteTypeId = 3; // Phone Note
                newNote.CreatedBy = identity.PersonId;
                newNote.ProviderID = identity.PersonId;
                // OK this is silly. Why should I set the PatientId property to chartId?
                // Bug in Progress Notes module. The call to AuditLog is passed in the PatientId
                // However, the method AuditLog.LogByChartId expects a chartId
                newNote.PatientId = chartId;
                newNote.Save();
            }
        }

        private string GetClinicalNote(string note) {
            return string.Format("<document><section><paragraph horizontalAlign='Left'><text>{0}</text></paragraph></section></document>",
                note);
        }
    }
}
