using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Collections;
using System.Configuration;
using System.Data;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;

using DataAccess;
using ResmedAVXHelper;

using RevampApi.Models;

namespace RevampApi.App_Code.AppModel
{
    /// <summary>
    /// Implement ResMed AVX Service calls
    /// </summary>
    public class CResmedAVXService : CVendorService
    {
        /// <summary>
        /// Base URL for the ResMed service
        /// </summary>
        private string m_strBaseAddress = String.Empty;

        /// <summary>
        /// ResMed AVX credentials
        /// </summary>
        private string m_strCredentials = String.Empty;

        /// <summary>
        /// Construct proxy for ResMed AVX service
        /// </summary>
        public CResmedAVXService()
        {
            System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
            System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
            LoadSystemSettings();
        }

        /// <summary>
        /// Load system setting for this service
        /// </summary>
        private void LoadSystemSettings()
        {
            CDataConnection cnn = null;
            string strConnectionString = String.Empty;
            bool bAudit = true;

            long lStatusCode = 0;
            string strStatusComment = String.Empty;

            //config settings
            strConnectionString = ConfigurationManager.ConnectionStrings["DBConnString"].ConnectionString;
            bAudit = (ConfigurationManager.AppSettings["AUDIT"] == "1") ? true : false;

            //connect to data source
            cnn = new CDataConnection();
            if (!cnn.Connect(strConnectionString, (int)DataConnectionType.Oracle, bAudit))
            {
                lStatusCode = 1;
                strStatusComment = "Error Connecting to Data Source";
                return;
            }


            //parameter list (BaseMstr.ASPSessionID, BaseMstr.ClientIP, BaseMstr.FXUserID);
            CDataParameterList pList = new CDataParameterList(String.Empty, String.Empty, 0);

            pList.AddInputParameter("pi_vParamList", "RESMED_AVX_BASEADDRESS,RESMED_AVX_CREDENTIALS");

            CDataSet cds = new CDataSet();
            DataSet ds = cds.GetOracleDataSet(cnn,
                                               "PCK_UTL_PARAMETERS.GetSystemParametersRS",
                                                pList,
                                                out lStatusCode,
                                                out strStatusComment);

            //check response
            if (lStatusCode == 0)
            {
                if (ds != null)
                {
                    foreach (DataTable table in ds.Tables)
                    {
                        foreach (DataRow row in table.Rows)
                        {
                            string strParamName = String.Empty;
                            string strParamValue = String.Empty;

                            strParamName = CDataUtils2.GetDSStringValue(row, "PARAMETER_NAME");
                            strParamValue = CDataUtils2.GetDSStringValue(row, "PARAMETER_VALUE");

                            if (!String.IsNullOrEmpty(strParamName))
                            {
                                switch (strParamName)
                                {
                                    case "RESMED_AVX_BASEADDRESS":
                                        m_strBaseAddress = strParamValue;
                                        break;

                                    case "RESMED_AVX_CREDENTIALS":
                                        m_strCredentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(strParamValue));
                                        break;
                                }
                            }
                        }
                    }
                }
            }
            
            //CLOSE CONNECTION
            cnn.Close();
        }

        /// <summary>
        /// Implement how to check if the service is active
        /// </summary>
        /// <returns></returns>
        public override ServiceStatus IsActive()
        {
            CHealtCheckMainResponse mainRespHealthCheck = null;
            string strMsg = String.Empty;
            ServiceStatus srvStatus = new ServiceStatus();

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(m_strBaseAddress);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage response = null;

                try
                {
                    response = client.GetAsync("healthCheck/status/").Result;
                    if (response.IsSuccessStatusCode)
                    {
                        mainRespHealthCheck = response.Content.ReadAsAsync<CHealtCheckMainResponse>().Result;
                        //strMsg = response.Content.ReadAsStringAsync().Result;
                    }
                    else
                    {
                        strMsg = response.ReasonPhrase;
                    }
                }
                catch (System.Net.Http.HttpRequestException e)
                {
                    if (!String.IsNullOrEmpty(e.Message))
                    {
                        strMsg = e.Message;
                    }
                    if (e.InnerException != null)
                    {
                        if (!String.IsNullOrEmpty(e.InnerException.Message))
                        {
                            strMsg += " " + e.InnerException.Message;
                        }
                    }
                }
                catch (System.AggregateException e)
                {
                    strMsg = e.Message;
                    if (e.InnerException != null)
                    {
                        if (!String.IsNullOrEmpty(e.InnerException.Message))
                        {
                            strMsg += " " + e.InnerException.Message;
                        }
                    }
                }

            }


            //build service status response
            if (mainRespHealthCheck != null && String.IsNullOrEmpty(strMsg))
            {
                srvStatus.active = "true";
                srvStatus.comment = "Code: " + mainRespHealthCheck.HealthChecks.Response.responseCode + ", " +
                                    "Desc: " + mainRespHealthCheck.HealthChecks.Response.responseDesc + ", " +
                                    "Release Version: " + mainRespHealthCheck.HealthChecks.Response.releaseVersion;
                srvStatus.statusCode = 0;
                srvStatus.statusComment = String.Empty;
            }
            else
            {
                srvStatus.active = "false";
                srvStatus.comment = String.Empty;
                srvStatus.statusCode = 1;
                srvStatus.statusComment = strMsg;
            }

            return srvStatus;
        }

        /// <summary>
        /// Search for a patient's CPAP data and try to fill CPAP gap, if any.
        /// </summary>
        /// <param name="strPatientID"></param>
        /// <param name="strExternalID"></param>
        /// <param name="dtProcessDate"></param>
        /// <param name="strGap"></param>
        /// <returns></returns>
        public override PatientLookupResponse LookupPatient(string strPatientID,
                                                            string strExternalID,
                                                            DateTime dtProcessDate,
                                                            string strGap)
        {
            PatientLookupResponse rsp = new PatientLookupResponse();
            string strMsg = String.Empty;
            CLookupMainResponse mainRespLookPatient = null;

            string strURI = String.Empty;
            string strEndDate = String.Empty;
            string strNoOfDays = String.Empty;

            //EndDate is YYYY-MM-DD format
            strEndDate = dtProcessDate.ToString("yyyy-MM-dd");

            //NoOfDays
            strNoOfDays = strGap;

            ////strEndDate = "2016-03-31";
            //strEndDate = "2016-06-30";
            //strNoOfDays = "90";

            //build URI
            strURI = "v1/patients/{0}/data/sessions?noOfDays={1}&endDate={2}";
            strURI = String.Format(strURI, strExternalID, strNoOfDays, strEndDate);

            //CALL service to get data...
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(m_strBaseAddress);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", m_strCredentials);

                HttpResponseMessage response = null;

                try
                {
                    response = client.GetAsync(strURI).Result;
                    if (response.IsSuccessStatusCode)
                    {
                        mainRespLookPatient = response.Content.ReadAsAsync<CLookupMainResponse>().Result;
                    }
                    else
                    {
                        rsp.statusCode = 1;
                        rsp.statusComment = response.ReasonPhrase;
                        return rsp;
                    }
                }
                catch (System.Net.Http.HttpRequestException e)
                {
                    if (!String.IsNullOrEmpty(e.Message))
                    {
                        strMsg = e.Message;
                    }
                    if (e.InnerException != null)
                    {
                        if (!String.IsNullOrEmpty(e.InnerException.Message))
                        {
                            strMsg += " " + e.InnerException.Message;
                        }
                    }

                    rsp.statusCode = 1;
                    rsp.statusComment = strMsg;
                    return rsp;
                }
            }

            //process CPAP data
            if (mainRespLookPatient != null)
            {
                if (mainRespLookPatient.Response != null)
                {
                    if (mainRespLookPatient.Response.responseDesc == "SUCCESS")
                    {
                        if (mainRespLookPatient.Response.patientData != null)
                        {
                            if (mainRespLookPatient.Response.patientData.ecn == strExternalID)
                            {
                                if (mainRespLookPatient.Response.patientData.sessionData != null)
                                {
                                    //process cpap data received
                                    ProcessCPAPData(strPatientID, strExternalID, mainRespLookPatient.Response.patientData.sessionData, ref rsp);
                                }
                                else
                                {
                                    rsp.recordCount = 0;
                                    //rsp.statusCode = 1;
                                    //rsp.statusComment = "No session data received";
                                }
                            }
                            else
                            {
                                rsp.recordCount = 0;
                                rsp.statusCode = 1;
                                rsp.statusComment = "ECN from response did not match";
                            }
                        }
                        else
                        {
                            rsp.recordCount = 0;
                        }
                    }
                    else
                    {
                        rsp.statusCode = 1;
                        rsp.statusComment = mainRespLookPatient.Response.responseDesc;
                    }
                }
                else
                {
                    rsp.statusCode = 1;
                    rsp.statusComment = "Incomplete response receive (level 2)";
                }
            }
            else
            {
                rsp.statusCode = 1;
                rsp.statusComment = "Incomplete response receive (level 1)";
            }

            return rsp;
        }

        /// <summary>
        /// Process CPAP data.
        /// </summary>
        /// <param name="strPatientID"></param>
        /// <param name="strExternalID"></param>
        /// <param name="lstSessionData"></param>
        /// <param name="rsp"></param>
        private void ProcessCPAPData(string strPatientID,
                                     string strExternalID,
                                     List<CSessionData> lstSessionData,
                                     ref PatientLookupResponse rsp)
        {
            long lRecordCount = 0; //new records count
            long lResult = 0;
            long lStatusCode = 0;
            string strStatusComment = String.Empty;

            CDataConnection cnn = null;
            string strConnectionString = String.Empty;
            bool bAudit = true;

            //config settings
            strConnectionString = ConfigurationManager.ConnectionStrings["DBConnString"].ConnectionString;
            bAudit = (ConfigurationManager.AppSettings["AUDIT"] == "1") ? true : false;

            //connect to data source
            cnn = new CDataConnection();
            if (!cnn.Connect(strConnectionString, (int)DataConnectionType.Oracle, bAudit))
            {
                rsp.statusCode = 1;
                rsp.statusComment = "Error Connecting to Data Source";
                return;
            }

            //process all 
            foreach (CSessionData session in lstSessionData)
            {
                CCPAP cpap = new CCPAP();

                //PatientID
                cpap.PatientID = strPatientID;

                //External ID
                cpap.ExternalID = strExternalID;

                //Therapy Date
                cpap.TherapyDate = session.sessionDate;

                //ReceiptTime
                cpap.ReceiptTime = session.receiptTime;

                //Device Serial No
                if (session.deviceID != null)
                {
                    cpap.DeviceMode = session.deviceID.mode;

                    if (session.deviceID.device != null)
                    {
                        cpap.DeviceSerialNo = session.deviceID.device.serialNo;
                        cpap.DeviceType = session.deviceID.device.deviceType;
                        cpap.DeviceTypeDesc = session.deviceID.device.deviceTypeDesc;
                    }
                }

                //Settings
                if (session.set != null)
                {
                    cpap.SettingPress = session.set.press;
                    cpap.SettingMaxPress = session.set.maxPress;
                    cpap.SettingMinPress = session.set.minPress;
                    cpap.SettingEPRType = session.set.EPRType;
                    cpap.SettingEPRLevel = session.set.EPRLevel;
                    cpap.SettingODIThreshold = session.set.ODIThreshold;
                    cpap.SettingIBREnable = session.set.iBREnable;
                    cpap.SettingEPAPAutoEnable = session.set.EPAPAutoEnable;
                    cpap.SettingIPAP = session.set.IPAP;
                    cpap.SettingEPAP = session.set.EPAP;
                    cpap.SettingAutoSetResponse = session.set.autosetResponse;
                    cpap.SettingMinEPAP = session.set.minEPAP;
                    cpap.SettingMaxEPAP = session.set.maxEPAP;
                    cpap.SettingMinPS = session.set.minPS;
                    cpap.SettingMaxPS = session.set.maxPS;
                }

                //Clinical metrics
                if (session.clinicalMetrics != null)
                {
                    cpap.SpontTriggBreaths = session.clinicalMetrics.spontTriggBreaths;
                    cpap.SpontCycledBreaths = session.clinicalMetrics.spontCycledBreaths;

                    if (session.clinicalMetrics.tgtIPAP != null)
                    {
                        cpap.TGTIPAP_95 = session.clinicalMetrics.tgtIPAP.ninetyfive;
                        cpap.TGTIPAP_50 = session.clinicalMetrics.tgtIPAP.median;
                        cpap.TGTIPAP_MAX = session.clinicalMetrics.tgtIPAP.max;
                    }

                    if (session.clinicalMetrics.tgtEPAP != null)
                    {
                        cpap.TGTEPAP_95 = session.clinicalMetrics.tgtEPAP.ninetyfive;
                        cpap.TGTEPAP_50 = session.clinicalMetrics.tgtEPAP.median;
                        cpap.TGTEPAP_MAX = session.clinicalMetrics.tgtEPAP.max;
                    }

                    if (session.clinicalMetrics.leak != null)
                    {
                        cpap.LEAK_95 = session.clinicalMetrics.leak.ninetyfive;
                        cpap.LEAK_50 = session.clinicalMetrics.leak.median;
                        cpap.LEAK_MAX = session.clinicalMetrics.leak.max;
                    }

                    if (session.clinicalMetrics.respRate != null)
                    {
                        cpap.RESPRATE_95 = session.clinicalMetrics.respRate.ninetyfive;
                        cpap.RESPRATE_50 = session.clinicalMetrics.respRate.median;
                        cpap.RESPRATE_MAX = session.clinicalMetrics.respRate.max;
                    }

                    if (session.clinicalMetrics.ieRatio != null)
                    {
                        cpap.IERATIO_95 = session.clinicalMetrics.ieRatio.ninetyfive;
                        cpap.IERATIO_50 = session.clinicalMetrics.ieRatio.median;
                        cpap.IERATIO_MAX = session.clinicalMetrics.ieRatio.max;
                    }

                    if (session.clinicalMetrics.minuteVent != null)
                    {
                        cpap.MINUTEVENT_95 = session.clinicalMetrics.minuteVent.ninetyfive;
                        cpap.MINUTEVENT_50 = session.clinicalMetrics.minuteVent.median;
                        cpap.MINUTEVENT_MAX = session.clinicalMetrics.minuteVent.max;
                    }

                    if (session.clinicalMetrics.tidalVol != null)
                    {
                        cpap.TIDALVOL_95 = session.clinicalMetrics.tidalVol.ninetyfive;
                        cpap.TIDALVOL_50 = session.clinicalMetrics.tidalVol.median;
                        cpap.TIDALVOL_MAX = session.clinicalMetrics.tidalVol.max;
                    }

                    if (session.clinicalMetrics.SPO2 != null)
                    {
                        cpap.SPO2_95 = session.clinicalMetrics.SPO2.ninetyfive;
                        cpap.SPO2_50 = session.clinicalMetrics.SPO2.median;
                        cpap.SPO2_MIN = session.clinicalMetrics.SPO2.min;
                        cpap.SPO2_minBelow88 = session.clinicalMetrics.SPO2.minutesBelow88percent;
                        cpap.SPO2_secBelowDYNAT = session.clinicalMetrics.SPO2.secondsBelowDynamicThreshold;
                    }

                    if (session.clinicalMetrics.alveolarVentilation != null)
                    {
                        cpap.ALVEOLARVENT_95 = session.clinicalMetrics.alveolarVentilation.ninetyfive;
                        cpap.ALVEOLARVENT_50 = session.clinicalMetrics.alveolarVentilation.median;
                        cpap.ALVEOLARVENT_MAX = session.clinicalMetrics.alveolarVentilation.max;
                    }

                }

                //Respiratory event indeces: AHI, HI, OAI, CAI, UAI
                if (session.respEvents != null)
                {
                    cpap.AHI = session.respEvents.AHI;
                    cpap.HI = session.respEvents.HI;
                    cpap.AI = session.respEvents.AI;
                    cpap.OAI = session.respEvents.OAI;
                    cpap.CAI = session.respEvents.CAI;
                    cpap.UAI = session.respEvents.UAI;
                    cpap.ODI = session.respEvents.ODI;
                    cpap.CSR = session.respEvents.CSR;
                    cpap.RERA = session.respEvents.RERA;
                }

                //Patient Interface
                if (session.patientInterface != null)
                {
                    cpap.Humidifier = session.patientInterface.humidifier;
                    cpap.HeatedTube = session.patientInterface.heatedTube;
                    cpap.AMBHumidity = session.patientInterface.ambHumidity;
                }



                //Usage
                if (session.usage != null)
                {
                    //Minutes of Use
                    cpap.MinOfUse = session.usage.duration;

                    //Mask On/Off
                    if (session.usage.maskOn != null && session.usage.maskOff != null)
                    {
                        if (session.usage.maskOn.Count == session.usage.maskOff.Count)
                        {
                            for (int idx = 0; idx < session.usage.maskOn.Count; idx++)
                            {
                                CCPAPUsage cpapUsage = new CCPAPUsage();
                                cpapUsage.MaskOn = session.usage.maskOn[idx];
                                cpapUsage.MaskOff = session.usage.maskOff[idx];
                                cpap.Usage.Add(cpapUsage);
                            }
                        }
                    }

                }

                //save
                if (cpap.MinOfUse != "0")
                {
                    lResult = cpap.Save(ref cnn, ref lStatusCode, ref strStatusComment);
                    if (lStatusCode != 0)
                    {
                        rsp.statusCode = lStatusCode;
                        rsp.statusComment = strStatusComment;
                        return;
                    }
                    else
                    {
                        lRecordCount += lResult;
                    }
                }

            }

            //CLOSE CONNECTION
            cnn.Close();

            rsp.recordCount = lRecordCount;
        }


        /// <summary>
        /// Search for the corresponding Patient ID use by the Vendor
        /// </summary>
        /// <param name="lstPatientData"></param>
        /// <returns></returns>
        public override PatientIDSearchResponse SearchPatientID(List<string> lstPatientData)
        {
            PatientIDSearchResponse rsp = new PatientIDSearchResponse();
            string strMsg = String.Empty;
            CSearchPatientIDMainResponse mainRespSearchPatientID = null;

            string strURI = String.Empty;
            string strDeviceSerialNo = String.Empty;
            string strDOB = String.Empty;

            //validate lstPatientData
            if (lstPatientData.Count != 2)
            {
                rsp.statusCode = 1;
                rsp.statusComment = "Wrong number of arguments";
                return rsp;
            }

            strDeviceSerialNo = lstPatientData[0];
            strDOB = lstPatientData[1];

            //build URI
            strURI = "v1/patients?device_serialNo={0}&dob={1}";
            strURI = String.Format(strURI, strDeviceSerialNo, strDOB);

            //CALL service to get data...
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(m_strBaseAddress);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", m_strCredentials);

                HttpResponseMessage response = null;

                try
                {
                    response = client.GetAsync(strURI).Result;
                    if (response.IsSuccessStatusCode)
                    {
                        mainRespSearchPatientID = response.Content.ReadAsAsync<CSearchPatientIDMainResponse>().Result;
                    }
                    else
                    {
                        rsp.statusCode = 1;
                        rsp.statusComment = response.ReasonPhrase;
                        return rsp;
                    }
                }
                catch (System.Net.Http.HttpRequestException e)
                {
                    if (!String.IsNullOrEmpty(e.Message))
                    {
                        strMsg = e.Message;
                    }
                    if (e.InnerException != null)
                    {
                        if (!String.IsNullOrEmpty(e.InnerException.Message))
                        {
                            strMsg += " " + e.InnerException.Message;
                        }
                    }

                    rsp.statusCode = 1;
                    rsp.statusComment = strMsg;
                    return rsp;
                }
            }

            //process response
            if (mainRespSearchPatientID != null)
            {
                if (mainRespSearchPatientID.Response != null)
                {
                    if (mainRespSearchPatientID.Response.responseDesc == "SUCCESS")
                    {
                        if (mainRespSearchPatientID.Response.searchResult != null)
                        {
                            PatientIDSearchResult r = new PatientIDSearchResult();
                            r.patientData = "Device Serial No.: " + strDeviceSerialNo + "; DOB: " + strDOB;
                            r.externalPatientID = mainRespSearchPatientID.Response.searchResult.ecn;
                            rsp.searchResult.Add(r);
                        }
                        else
                        {
                            rsp.statusCode = 0;
                            rsp.statusComment = "No results";
                        }
                    }
                    else
                    {
                        rsp.statusCode = 1;
                        rsp.statusComment = mainRespSearchPatientID.Response.responseDesc;
                    }
                }
                else
                {
                    rsp.statusCode = 1;
                    rsp.statusComment = "Incomplete response receive (level 2)";
                }
            }
            else
            {
                rsp.statusCode = 1;
                rsp.statusComment = "Incomplete response receive (level 1)";
            }

            return rsp;
        }

    }
}