

package gov.va.med.cds.integration.vim.ha;


import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;
import gov.va.med.cds.testharness.vhim400.builders.BaseDatatypesBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDataBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDomainBuilderFactoryInterface;
import gov.va.med.cds.testharness.vhim400.builders.FilterBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAGoalTrackingBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAGoalTrackingBuilderFactory;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.Test;
import org.junit.runner.RunWith;

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


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndGoalTrackingTest
    extends
        AbstractHealthAdapterEndToEndTest
{
    private static final String GOAL_TRACKING_DOMAINENTRYPOINT_XPATH = "//goalsTracking";
    private static final String SPECIALIZED_DOMAIN_ENTRY_POINT = "filter:goalTrackingDomainEntryPointFilter";
    private static final String GOAL_NAME_1 = "Walk Daily";
    private static final String GOAL_NAME_2 = "Deep Breathing";
    private static final String GOAL_NAME_KEY = "goalName";


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateReadUpdateAndDeleteGoalTracking( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        String createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, null );

        Document clinicalDataDocument = createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        // Check for record identifiers in the response for the newly created record(s)
        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        String recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();

        // Read back the created record
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "GoalTracking" );

        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, null, null, SPECIALIZED_DOMAIN_ENTRY_POINT );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 1 );

        filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, START_DATE, START_DATE, SPECIALIZED_DOMAIN_ENTRY_POINT );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 1 );

        // Update pain event entry
        String updateRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_UPDATE_TEMPLATE_ID, recordIdentifier, GOAL_NAME_2, null );
        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( HA_UPDATE_TEMPLATE_ID, updateRequestXml, "GOAL_TRACKING", "GOAL_TRACKING_ID" );
        assertNotNull( clinicalDataDocumentUpdate );

        // Logically Delete pain event entry
        String logicalDeleteXml = createHADeleteXml( "GoalTracking", HA_DELETE_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, logicalDeleteXml, "GOAL_TRACKING", "GOAL_TRACKING_ID", true );

        // Physically Delete pain event entry
        String physicalDeleteXml = createHADeleteXml( "GoalTracking", HA_DELETE_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( HA_DELETE_TEMPLATE_ID, physicalDeleteXml, "GOAL_TRACKING", "GOAL_TRACKING_ID", false );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testReadGoalTrackingByPatientId( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );
        doDelete( uniquePatientIdentity + "000" );

        String createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120618090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120619090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120620090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity + "000", "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120620090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_2, "20120614090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_2, "20120616090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_2, "20120616110000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        // Read back the created record
        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "GoalTracking" );

        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, null, null, SPECIALIZED_DOMAIN_ENTRY_POINT );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 2 );

        filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, "2012-06-18", "2012-06-19", SPECIALIZED_DOMAIN_ENTRY_POINT );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 1 );

        filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, "2012-06-16", "2012-06-20", SPECIALIZED_DOMAIN_ENTRY_POINT );
        readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 2 );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testReadGoalTrackingByPatientIdAndGoalName( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        String createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120618090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120619090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        createRequestXml = createHACreateXml( uniquePatientIdentity, "GoalTracking", HA_CREATE_TEMPLATE_ID, null, GOAL_NAME_1, "20120620090000-0700" );
        createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        // Read back the created record
        String[] hdrPatient = { ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, uniquePatientIdentity };
        String[][] patientIdentifiers = { hdrPatient };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

        Map<String, String> entryPointFilter = new HashMap<String, String>();
        entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "GoalTracking" );
        entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "ID_1" );

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

        Map<String, String> optionalQueryParameters = new HashMap<String, String>();
        optionalQueryParameters.put( GOAL_NAME_KEY, GOAL_NAME_1 );

        String filterXml = FilterBuilder.buildFilterWithEdiPi( FILTER_ID, entryPointFilterMaps, patients, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ),
                        SPECIALIZED_DOMAIN_ENTRY_POINT, optionalQueryParameters );

        readAndAssertDomainData( null, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 3 );

        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-06-19Z" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-06-20Z" );
        entryPointFilterMaps.clear();
        entryPointFilterMaps.add( entryPointFilter );

        filterXml = FilterBuilder.buildFilterWithEdiPi( FILTER_ID, entryPointFilterMaps, patients, DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ), SPECIALIZED_DOMAIN_ENTRY_POINT,
                        optionalQueryParameters );
        readAndAssertDomainData( null, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 2 );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testGoalTracking_EmptyCompletionPercent( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        String createRequestXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\"><templateId>HealthAdapterCreate1</templateId><patient><goalsTracking><goalTracking><patient><identifier><identity>" + uniquePatientIdentity + "</identity><assigningFacility>200DOD</assigningFacility><assigningAuthority>USDOD</assigningAuthority></identifier><name><prefix>Prefix</prefix><given>Given</given><middle>MiddleName</middle><family>FamilyName</family><suffix>Suffix</suffix><title>Title</title></name></patient><entryDate><literal>20120618090000-0700</literal></entryDate><completionPercent>a</completionPercent><comments>comments</comments><dataEnterer>dataEnterer</dataEnterer><allowAccessByClinicalStaff>true</allowAccessByClinicalStaff><goalName>Walk Daily</goalName><goalType>goalType</goalType><goalDetails>goalDetails</goalDetails></goalTracking></goalsTracking></patient></clinicaldata:ClinicalData>";
        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestXml, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createXmlRequestId );
        // Check for schema validation error
        assertTrue( clinicalDataDocument.selectNodes( FATAL_ERRORS_EXCEPTIONS_XPATH ).size() > 0 );

        createRequestXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\"><templateId>HealthAdapterCreate1</templateId><patient><goalsTracking><goalTracking><patient><identifier><identity>" + uniquePatientIdentity + "</identity><assigningFacility>200DOD</assigningFacility><assigningAuthority>USDOD</assigningAuthority></identifier><name><prefix>Prefix</prefix><given>Given</given><middle>MiddleName</middle><family>FamilyName</family><suffix>Suffix</suffix><title>Title</title></name></patient><entryDate><literal>20120618090000-0700</literal></entryDate><completionPercent></completionPercent><comments>comments</comments><dataEnterer>dataEnterer</dataEnterer><allowAccessByClinicalStaff>true</allowAccessByClinicalStaff><goalName>Walk Daily</goalName><goalType>goalType</goalType><goalDetails>goalDetails</goalDetails></goalTracking></goalsTracking></patient></clinicaldata:ClinicalData>";
        clinicalDataDocument = createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "GoalTracking" );

        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, null, null, SPECIALIZED_DOMAIN_ENTRY_POINT );
        clinicalDataDocument = readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 1 );

        assertTrue( clinicalDataDocument.selectSingleNode( "//goalsTracking/goalTracking/completionPercent" ).getText().equals( "0" ) );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testGoalTrackingWithMandatoryElements( )
        throws Exception
    {
        doDelete( uniquePatientIdentity );

        String createRequestXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\"><templateId>HealthAdapterCreate1</templateId><patient><goalsTracking><goalTracking><patient><identifier><identity>" + uniquePatientIdentity + "</identity><assigningFacility>200DOD</assigningFacility><assigningAuthority>USDOD</assigningAuthority></identifier><name/></patient><entryDate><literal>20120618090000-0700</literal></entryDate></goalTracking></goalsTracking></patient></clinicaldata:ClinicalData>" ;
        Document clinicalDataDocument = createAndAssertDomainData( HA_CREATE_TEMPLATE_ID, createRequestXml );

        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( "ID_1", "GoalTracking" );

        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "GoalTracking", FILTER_ID, null, null, SPECIALIZED_DOMAIN_ENTRY_POINT );
        clinicalDataDocument = readAndAssertDomainData( assigningAuthorityAndFacilityMap, HA_READ_TEMPLATE_ID, filterXml, FILTER_ID, GOAL_TRACKING_DOMAINENTRYPOINT_XPATH, 1 );

        assertTrue( clinicalDataDocument.selectSingleNode( "//goalsTracking/goalTracking/completionPercent" ).getText().equals( "0" ) );
        assertTrue( clinicalDataDocument.selectSingleNode( "//goalsTracking/goalTracking/allowAccessByClinicalStaff" ).getText().equals( "true" ) );
    }


    private void doDelete( String patientId )
    {
        hdrJdbcTemplate.update( "DELETE FROM GOAL_TRACKING WHERE PATIENT_IDENTITY = '" + patientId + "'" );
    }


    private String createHACreateXml( String patientIdentifier, String entryPoint, String templateId, String recordIdentifier, String goalName, String entryDate )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.GoalTracking );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAGoalTrackingBuilderFactory factory = new HAGoalTrackingBuilderFactory();
        factory.setGoalTrackingBuilder( new HAGoalTrackingBuilder( recordIdentifier, goalName, entryDate ) );
        domainEntryPointsWrappersMap.put( "GoalTracking", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

        Element patient = null;
        if ( patientIdentifier == null )
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest" );
        }
        else
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest", patientIdentifier );
        }

        Document vdmClinicalDataInsert = clinicalDataBuilder.createClinicalData( templateId, 1, patient );

        return vdmClinicalDataInsert.asXML();
    }


    protected String createHADeleteXml( String entryPoint, String templateId, String recordIdentifierIdentity, String recordStatus )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.GoalTracking );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAGoalTrackingBuilderFactory factory = new HAGoalTrackingBuilderFactory();
        factory.setGoalTrackingBuilder( new HAGoalTrackingBuilder() );

        domainEntryPointsWrappersMap.put( "GoalTracking", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

        Element patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "HealthAdapterTest", "200DOD", "USDOD" );
        Document clinicalDataInsert = clinicalDataBuilder.deleteClinicalData( domainEntryPointsMap.get( templateId ), templateId, patient, recordIdentifierIdentity, recordStatus );

        return clinicalDataInsert.asXML();
    }
}
