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.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.HAPainAssessmentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAPainAssessmentBuilderFactory;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.junit.Test;


public class EndToEndPainAssessmentTest 
	extends
       AbstractHealthAdapterEndToEndTest
   {
	
	 private static final Log LOGGER = LogFactory.getLog( EndToEndPainAssessmentTest.class );
	 
	 private String PATIENT_DOMAINENTRYPOINT_XPATH = "/clinicaldata:ClinicalData/patients/patient/painAssessments/painAssessment";
	 
	    @SuppressWarnings( "unchecked" )
	    @Test
	    @Suite( groups = { "deprecatedtest" } )
	    public void testCreateReadUpdateAndDeletePainAssessment( )
	        throws Exception
	    {
	    	doDelete( uniquePatientIdentity );

	        String createRequestXml = createPainAssessmentCreateXml( uniquePatientIdentity, "PainAssessment", TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, null );


	        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_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 create record
	        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

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

	        String filterXml = createHAFilter( uniquePatientIdentity, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "PainAssessment",
	                        TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, null, null );

	        readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID, filterXml, TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER,
	        		PAIN_ASSESSMENT_XPATH, 1 );


	        // Update Pain Assessment Record
	        String updateRequestXml = createPainAssessmentCreateXml( uniquePatientIdentity, "PainAssessment", TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, recordIdentifier, "UPDATE" );
	        Document clinicalDataDocumentUpdate = updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml, "PAIN_ASSESSMENT", "PAIN_ASSESSMENT_ID");
	        assertNotNull( clinicalDataDocumentUpdate );

	        
	     // Logically Delete Pain Assessment Record
	        String logicalDeleteXml = createPainAssessmentDeleteXml( "PainAssessment", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
	        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, logicalDeleteXml, "PAIN_ASSESSMENT", "PAIN_ASSESSMENT_ID", true );

	        
	        // Physically Delete Pain Assessment Record
	        String physicalDeleteXml = createPainAssessmentDeleteXml( "AssessmentTotalScore", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
	        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, physicalDeleteXml, "ASSESSMENT_TOTAL_SCORE", "ASSESSMENT_TOTAL_SCORE_ID", false );

	    }
	    
	    
	    @SuppressWarnings( "unchecked" )
	    @Test
	    @Suite( groups = { "deprecatedtest" } )
	    public void testCRUDPainReassessment_RatingError( )
	        throws Exception
	    {
	        hdrJdbcTemplate.update( "delete from pain_assessment where patient_identity like '" + uniquePatientIdentity + "%'" );
	        requestProcessor.setValidateReadResponseXML( true );
	        createXmlRequestId = new UniqueIdentifier().toString();

	        // Create a request that includes a null <rating/> element
	        String createRequestNullRating = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <templateId>HealthAdapterCreate1</templateId> <patient> <painAssessments> <painAssessment> <patient> <identifier> <identity>Identity</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> <assessmentDate> <literal>19691231170000-0700</literal> </assessmentDate> <avgPainLevel> <rating/> <question/> </avgPainLevel> <dataEnterer>dataEnterer</dataEnterer> <allowAccessByClinicalStaff>true</allowAccessByClinicalStaff> </painAssessment> </painAssessments> </patient> </clinicaldata:ClinicalData>";
	        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestNullRating, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createXmlRequestId );

	        // This should NOT throw a validation error
	        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
	        assertTrue( recordIdentifierList.size() > 0 );
	        
	        // Create a request that includes an alpha char in a <rating> field
	        String createRequestXmlAlphaChar = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <clinicaldata:ClinicalData xmlns:clinicaldata=\"Clinicaldata\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"> <templateId>HealthAdapterCreate1</templateId> <patient> <painAssessments> <painAssessment> <patient> <identifier> <identity>Identity</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> <assessmentDate> <literal>19691231170000-0700</literal> </assessmentDate> <avgPainLevel> <rating>Rating</rating> <question>Question</question> </avgPainLevel> <dataEnterer>dataEnterer</dataEnterer> <allowAccessByClinicalStaff>true</allowAccessByClinicalStaff> </painAssessment> </painAssessments> </patient> </clinicaldata:ClinicalData>";
	        clinicalDataDocument = requestProcessor.createClinicalData( createRequestXmlAlphaChar, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createXmlRequestId );
	        
	        // Check for schema validation error
	        List<Element> fatalErrorList = clinicalDataDocument.selectNodes( FATAL_ERRORS_EXCEPTIONS_XPATH );
	        assertTrue( fatalErrorList.size() > 0 );
	    }
	    
	    
	    
	    @Test
	    @Suite( groups = { "deprecatedtest" } )
	    @SuppressWarnings( "unchecked" )
	    public void testReadPainAssessment( )
	        throws Exception
	    {
	        Map<String, String> assigningAuthorityAndFacilityMap = new HashMap<String, String>();

	        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
	        entryPointFilterMap.put( "ID_1", "PainAssessment" );
	        entryPointFilterMap.put( FilterBuilder.QUERY_TIMEOUT_SECONDS, QUERY_TIMOUT_SECONDS_MAX );

	        String filterXml = createHAFilter( TEST_READ_PATIENTIDENTITY_HDR, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR,
	                        "PainAssessment", TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, null, null );

	        if ( LOGGER.isDebugEnabled() )
	        {
	            LOGGER.debug( "filterXml - " + filterXml );
	        }

	        Document clinicalDataDocument = readAndAssertDomainData( assigningAuthorityAndFacilityMap, TemplateIdHelper.HEALTH_ADAPTER_READ1_TEMPLATE_ID,
	                        filterXml, TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER );

	        List<Element> patientsList = clinicalDataDocument.selectNodes( PATIENT_IDENTITY_XPATH );
	        assertTrue( patientsList.size() > 0 );
	    }

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

	    
         
	    private String createPainAssessmentCreateXml( String patientIdentifier, String entryPoint, String templateId, String recordIdentifier, String category )
	    {
	        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
	        domainEntryPointsMap.put( templateId, DomainEntryPoint.PainAssessment );
	        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
	        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

	        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
	        HAPainAssessmentBuilderFactory factory = new HAPainAssessmentBuilderFactory();
	        if ( category != null )
	        {
	            
	            factory.setPainAssessmentBuilder(new HAPainAssessmentBuilder(recordIdentifier, category));
	        }
	        else
	        {
	            factory.setPainAssessmentBuilder( new HAPainAssessmentBuilder( recordIdentifier ) );

	        }
	        domainEntryPointsWrappersMap.put( "PainAssessment", factory );
	        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

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

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

	        return clinicalDataInsert.asXML();
	    }

	    
	    

		
		
		 private String createPainAssessmentDeleteXml( String entryPoint, String templateId, String recordIdentifierIdentity, String recordStatus )
		    {
		        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
		        domainEntryPointsMap.put( templateId, DomainEntryPoint.PainAssessment);
		        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
		        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

		        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
		        HAPainAssessmentBuilderFactory factory = new HAPainAssessmentBuilderFactory();
		        factory.setPainAssessmentBuilder(new HAPainAssessmentBuilder());

		        domainEntryPointsWrappersMap.put( "PainAssessment", 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();
		    }
		 
		 
		 @SuppressWarnings( "unchecked" )
		    protected Document readAndAssertDomainData( Map<String, String> assigningFacilityAndPatientIdentityMap, String templateId, String filter, String filterId )
		        throws Exception
		    {
		        Document clinicalDataDocument = super.readAndAssertDomainData( filter );

		        // Check for domain entry point elements
		        List<Element> domainElements = clinicalDataDocument.selectNodes( PATIENT_DOMAINENTRYPOINT_XPATH );
		        assertTrue( domainElements.size() > 0 );

		        return clinicalDataDocument;
		    }



}
