

package gov.va.med.cds.integration.vhim400;


import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.integration.AbstractEndToEndTest;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.request.TemplateRequestProcessor;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;
import gov.va.med.cds.testharness.vhim400.builders.FilterBuilder;
import gov.va.med.cds.testharness.xml.Assert;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndReadVitalsHdrVistaTest
    extends
        AbstractEndToEndTest
{
    private static final String PATIENT_IDENTITY_HDR1 = "test_sourceid_3";
    private static final String PATIENT_IDENTITY_HDR2 = "test_sourceid_2";
    private static final String PATIENT_IDENTITY_HDR3 = "test_sourceid_11";
    private static final String ASSIGNING_FACILITY_HDR = "605";
    private static final String ASSIGNING_FACILITY_HDR_VISTA = "580";
    private static final String ASSIGNING_AUTHORITY_HDR_1 = "USVHA";
    private static final String ASSIGNING_AUTHORITY_HDR = "USDOD";

    private static final String PATIENT_IDENTITY_VISTA123 = "123";
    private static final String PATIENT_IDENTITY_VISTA260 = "260";
    private static final String PATIENT_IDENTITY_VISTA410 = "410";
    private static final String ASSIGNING_FACILITY_VISTA = "580";
    private static final String ASSIGNING_AUTHORITY_VISTA = "USVHA";

    private static final String XPATH_ERRORSECTION = "/clinicaldata:ClinicalData/errorSection";
    private static final String XPATH_PATIENTS = "//patients";
    private static final String XPATH_PATIENT = "//patient";
    private static final String XPATH_IDENTIFIERS = "//requestedResolvedIdentifiers";
    private static final String XPATH_VITALSIGNS_OBSERVATION_EVENTS = "//vitalSignObservationEvents";

    private static final String ASSIGNING_AUTHORITY_ELEMENT_NAME = "assigningAuthority";
    private static final String ASSIGNING_FACILITY_ELEMENT_NAME = "assigningFacility";
    private static final String PATIENT_IDENTITY_ELEMENT_NAME = "identity";

    protected static String XPATH_DIVISION_CODE = "//division/code";
    protected static String XPATH_RECORDIDENTIFIER_IDENTITY = "//recordIdentifier/identity";
    protected static String XPATH_OBSERVATIONTIME_LITERAL = "//observationTime/literal";
    protected static String XPATH_STATUS = "//status";
    protected static String XPATH_OBSVCHAR_DISPLAYTEXT = "//observedCharacteristic/displayText";
    protected static String XPATH_HOMETELEHEALTH_VENDOR = "//homeTelehealthMonitor/vendor";
    protected static String XPATH_HOMETELEHEALTH_HOME_APPLICANCE = "//homeTelehealthMonitor/homeAppliance";
    protected static String XPATH_HOMETELEHEALTH_MESURMENT_DEVICE = "//homeTelehealthMonitor/measurementDevice";
    protected static String XPATH_OBSERVATION_VALUE = "//vitalSignObservation/value";
    protected static String XPATH_OBSERVATION_UNIT_DISPALYTEXT = "//vitalSignObservation/unit/displayText";
    protected static String XPATH_OBSERVATION_QUALIFIER_VALUE_DISPLATEXT = "//vitalSignObservation/qualifier/value/displayText";
    protected static String XPATH_RECORDSOURCE_NAMESPACEID = "//recordSource/namespaceId";

    private static final String VITALS_HTH_XPATH = "vitalSignObservationEvents[((recordSource/namespaceId[starts-with(., '200T')]) and (status != 'E'))]";
    private static final String VITALS_VISTA_XPATH = "vitalSignObservationEvents[((recordSource/namespaceId[not(starts-with(.,'200T'))]) and (status != 'E'))]";

    protected TemplateRequestProcessor templateRequestProcessor;

    @Autowired
    private JdbcTemplate hdrJdbcTemplate;


    @Before
    @Suite( groups = { "checkintest" } )
    public void beforeEndToEndReadHdrVistaTestClassSetUp( )
        throws Exception
    {
        templateRequestProcessor = ( TemplateRequestProcessor )getRequestProcessor();
    }

    @Test
    @Suite( groups = { "checkintest" } )
    public void testHdrVistaVWVitalsignsRead40010( )
        throws Exception
    {
        String readTemplateId = TemplateIdHelper.VW_VITALSIGNS_READ_TEMPLATE_ID;
        String filterId = TemplateIdHelper.VW_VITAL_SINGLE_PATIENT_FILTER;

        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String[] hdrPatient = { ASSIGNING_AUTHORITY_HDR, ASSIGNING_FACILITY_HDR, PATIENT_IDENTITY_HDR1 };
        String[] vistaPatient5211 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA, PATIENT_IDENTITY_VISTA123 };
        String[] vistaPatient5212 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA, PATIENT_IDENTITY_VISTA260 };

        String[][] patientIdentifiers = { vistaPatient5211, vistaPatient5212, hdrPatient };

        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "VitalSignObservationEvent" );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "testQueryName" );
        entryPointFilterMap.put( FilterBuilder.START_DATE_KEY, "1950-03-16" );
        entryPointFilterMap.put( FilterBuilder.END_DATE_KEY, "2050-06-30" );
        entryPointFilterMap.put( FilterBuilder.X_PATH_KEY, FilterBuilder.VITALS_XPATH );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMap );

        Document clinicalDataDocument = readAndAssertDomainData( readTemplateId, filterId, requestId, entryPointFilterMaps, resolvedPatients, null,
                        null );
    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testMHVVitalsignsRead40010( )
        throws Exception
    {
        String readTemplateId = TemplateIdHelper.MHV_VITALSIGNS_READ_TEMPLATE_ID;
        String filterId = TemplateIdHelper.MHV_VITAL_SINGLE_PATIENT_FILTER;

        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String[] hdrPatient = { "USVHA", ASSIGNING_FACILITY_HDR, PATIENT_IDENTITY_HDR2 };
        String[] vistaPatient5211 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA, PATIENT_IDENTITY_VISTA123 };
        String[] vistaPatient5212 = { ASSIGNING_AUTHORITY_VISTA, ASSIGNING_FACILITY_VISTA, PATIENT_IDENTITY_VISTA260 };

        String[][] patientIdentifiers = { vistaPatient5211, vistaPatient5212, hdrPatient };

        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "VitalSignObservationEvent" );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "testQueryName" );
        entryPointFilterMap.put( FilterBuilder.X_PATH_KEY, FilterBuilder.VITALS_XPATH );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMap );

        Document clinicalDataDocument = readAndAssertDomainData( readTemplateId, filterId, requestId, entryPointFilterMaps, resolvedPatients, null,
                        null );
        assertTrue( clinicalDataDocument.selectNodes( XPATH_OBSERVATION_VALUE ).size() > 0 );
        assertTrue( clinicalDataDocument.selectNodes( XPATH_OBSERVATION_UNIT_DISPALYTEXT ).size() > 0 );
        assertTrue( clinicalDataDocument.selectNodes( XPATH_OBSERVATION_QUALIFIER_VALUE_DISPLATEXT ).size() > 0 );
        assertTrue( clinicalDataDocument.selectNodes( XPATH_RECORDSOURCE_NAMESPACEID ).size() > 0 );
        assertTrue( !clinicalDataDocument.asXML().contains( "<status>E</status>" ) );
        assertTrue( !clinicalDataDocument.asXML().contains( "<exceptionMessage>READ_QUERY_STRATEGY_NULL_FAILURE</exceptionMessage>" ) );

    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testHdrVitalsRead( )
        throws Exception
    {
        String readTemplateId = TemplateIdHelper.VITALSIGNS_READ_TEMPLATE_ID;
        String filterId = TemplateIdHelper.VITAL_SINGLE_PATIENT_ALL_DATA_FILTER;

        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String[] patient1 = { "USVHA", "605", "test_sourceid_3" };
        String[] patient2 = { "USVHA", "660", "test_sourceid_11" };
        String[] patient3 = { "USVHA", "580", "test_sourceid_11" };

        String[][] patientIdentifiers = { patient1, patient2, patient3 };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "VitalSignObservationEvent" );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "testQueryName" );
        entryPointFilterMap.put( FilterBuilder.START_DATE_KEY, "2000-03-16" );
        entryPointFilterMap.put( FilterBuilder.END_DATE_KEY, "2017-06-30" );
        entryPointFilterMap.put( FilterBuilder.X_PATH_KEY, FilterBuilder.VITALS_XPATH );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMap );
        Document clinicalDataDocument = readAndAssertDomainData( readTemplateId, filterId, requestId, entryPointFilterMaps, resolvedPatients, null,
                        FilterBuilder.VITALS_XPATH );

    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testHdrHTHVitalsRead( )
        throws Exception
    {
        String readTemplateId = TemplateIdHelper.VITALSIGNS_READ_TEMPLATE_ID;
        String filterId = TemplateIdHelper.VITAL_SINGLE_PATIENT_ALL_DATA_FILTER;

        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String[] hdrPatient = { ASSIGNING_AUTHORITY_HDR_1, ASSIGNING_FACILITY_HDR, PATIENT_IDENTITY_HDR1 };
        String[][] patientIdentifiers = { hdrPatient };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "VitalSignObservationEvent" );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "testQueryName" );
        entryPointFilterMap.put( FilterBuilder.START_DATE_KEY, "2000-03-16" );
        entryPointFilterMap.put( FilterBuilder.END_DATE_KEY, "2017-06-30" );
        entryPointFilterMap.put( FilterBuilder.X_PATH_KEY, VITALS_HTH_XPATH );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMap );

        Map<String, String> otherQueryParametersMap = new HashMap<String, String>();
        otherQueryParametersMap.put( "vitalSignType", "TEMPERATURE" );

        Document clinicalDataDocument = readAndAssertDomainData( readTemplateId, filterId, requestId, entryPointFilterMaps, resolvedPatients,
                        otherQueryParametersMap, VITALS_HTH_XPATH );

        List<Element> recNamespaceId = clinicalDataDocument.selectNodes( XPATH_RECORDSOURCE_NAMESPACEID );
        Element el = recNamespaceId.get( 0 );
        assertTrue( el.getStringValue().startsWith( "200T" ) );

    }


    @Test
    @Suite( groups = { "checkintest" } )
    public void testHdrVitalsReadInvalidType( )
        throws Exception
    {
        String readTemplateId = TemplateIdHelper.VITALSIGNS_READ_TEMPLATE_ID;
        String filterId = TemplateIdHelper.VITAL_SINGLE_PATIENT_ALL_DATA_FILTER;

        String requestId = TemplateIdHelper.getUniqueIdentifier();

        String[] hdrPatient = { ASSIGNING_AUTHORITY_HDR_1, ASSIGNING_FACILITY_HDR, PATIENT_IDENTITY_HDR1 };
        String[][] patientIdentifiers = { hdrPatient };
        List<Map<String, String>> resolvedPatients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "VitalSignObservationEvent" );
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "testQueryName" );
        entryPointFilterMap.put( FilterBuilder.START_DATE_KEY, "2000-03-16" );
        entryPointFilterMap.put( FilterBuilder.END_DATE_KEY, "2017-06-30" );
        entryPointFilterMap.put( FilterBuilder.X_PATH_KEY, VITALS_HTH_XPATH );

        List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
        entryPointFilterMaps.add( entryPointFilterMap );

        Map<String, String> otherQueryParametersMap = new HashMap<String, String>();
        otherQueryParametersMap.put( "vitalSignType", "TEMPERATURE UPDATE SELECT WEIGHT" );

        Document clinicalDataDocument = readData( readTemplateId, filterId, requestId, entryPointFilterMaps, resolvedPatients,
                        otherQueryParametersMap, "VITALS_HTH_XPATH" );

        assertTrue( clinicalDataDocument.asXML().contains( "<errorCode>INVALID_OTHER_QUERY_PARAMS" ) );

    }


    protected Document readAndAssertDomainData( String templateId, String filterId, String requestId, List<Map<String, String>> entryPointFilterMaps,
                    List<Map<String, String>> resolvedPatients, Map<String, String> optionalParamsMap, String xpath )
        throws Exception
    {
        Document clinicalDataDocument = readData( templateId, filterId, requestId, entryPointFilterMaps, resolvedPatients, optionalParamsMap, xpath );

        chkXML( resolvedPatients, clinicalDataDocument );

        return clinicalDataDocument;
    }


    private Document readData( String templateId, String filterId, String requestId, List<Map<String, String>> entryPointFilterMaps,
                    List<Map<String, String>> resolvedPatients, Map<String, String> optionalParamsMap, String xpath )
    {
        Document clinicalDataDocument = sendRequest( templateId, filterId, requestId, entryPointFilterMaps, resolvedPatients, optionalParamsMap,
                        xpath );

        return clinicalDataDocument;
    }


    private Document sendRequest( String templateId, String filterId, String requestId, List<Map<String, String>> entryPointFilterMaps,
                    List<Map<String, String>> resolvedPatients, Map<String, String> optionalParamsMap, String xpath )
    {
        String filterXml = null;

        if ( !filterId.equals( TemplateIdHelper.VITAL_SINGLE_PATIENT_ALL_DATA_FILTER ) )
        {
            filterXml = FilterBuilder.buildFilterWithResolvedIdentfiers( filterId, entryPointFilterMaps, resolvedPatients,
                            DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ) );

        }
        else
        {
            filterXml = FilterBuilder.buildFilterWithAddionalParms( filterId, entryPointFilterMaps, resolvedPatients,
                            DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ), optionalParamsMap, xpath );

        }

        templateRequestProcessor.setValidateReadResponseXML( true );
        Document clinicalDataDocument = templateRequestProcessor.readClinicalData( templateId, filterXml, filterId, requestId );
        assertNotNull( clinicalDataDocument );
        String clinicalDataXml = clinicalDataDocument.asXML();
        Assert.assertXmlValidation( clinicalDataXml, templateId );
        return clinicalDataDocument;
    }


    private void chkXML( List<Map<String, String>> resolvedPatients, Document clinicalDataDocument )
    {
        // Check for domain entry point elements
        List<Element> domainElements = clinicalDataDocument.selectNodes( XPATH_PATIENT );
        assertTrue( domainElements.size() > 0 );

        // Assert that the resolved identifier assigning facility values from the filter are in the result document
        List<Element> resultsResolvedIdentifiersList = clinicalDataDocument.selectNodes( XPATH_IDENTIFIERS );
        for ( Element resultsResolvedIdentifiers : resultsResolvedIdentifiersList )
        {
            String resultsAssigningAuthority = resultsResolvedIdentifiers.element( ASSIGNING_AUTHORITY_ELEMENT_NAME ).getText();
            String resultsAssigningFacility = resultsResolvedIdentifiers.element( ASSIGNING_FACILITY_ELEMENT_NAME ).getText();
            String resultsPatientIdentity = resultsResolvedIdentifiers.element( PATIENT_IDENTITY_ELEMENT_NAME ).getText();

            Map<String, String> assigningAuthorityFacilityAndPatientIdentityMap = null;
            for ( Map<String, String> resolvedPatientMap : resolvedPatients )
            {
                String mapAssigningAuthority = resolvedPatientMap.get( FilterBuilder.ASSIGNING_AUTHORITY_KEY );
                String mapAssigningFacility = resolvedPatientMap.get( FilterBuilder.ASSIGNING_FACILITY );
                String mapIdentity = resolvedPatientMap.get( FilterBuilder.IDENTITY );
                if ( mapAssigningAuthority != null && mapAssigningAuthority.equalsIgnoreCase( resultsAssigningAuthority )
                                && mapAssigningFacility != null && mapAssigningFacility.equalsIgnoreCase( resultsAssigningFacility )
                                && mapIdentity != null && mapIdentity.equalsIgnoreCase( resultsPatientIdentity ) )
                {
                    assigningAuthorityFacilityAndPatientIdentityMap = resolvedPatientMap;
                    break;
                }
            }

            assertNotNull( assigningAuthorityFacilityAndPatientIdentityMap );
            String mapPatientIdentity = assigningAuthorityFacilityAndPatientIdentityMap.get( FilterBuilder.IDENTITY );
            assertNotNull( mapPatientIdentity );
            assertTrue( mapPatientIdentity.equals( resultsPatientIdentity ) );
        }

        List<Element> vsoeElements = clinicalDataDocument.selectNodes( XPATH_VITALSIGNS_OBSERVATION_EVENTS );
        assertTrue( vsoeElements.size() > 0 );
    }

}
