

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


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.HAAssessmentDocumentBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HAAssessmentDocumentBuilderFactory;

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.Test;
import org.junit.runner.RunWith;


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndAssessmentDocumentTest
    extends
        AbstractHealthAdapterEndToEndTest
{
    private static String READ_TEST_DOMAINENTRYPOINT_XPATH = "//assessmentDocuments/assessmentDocument";
    private static final String SPECIALIZED_DOMAIN_ENTRY_POINT = "filter:assessmentDocumentDomainEntryPointFilter";
    private static final String CATEGORY_KEY = "category";
    private static final String CATEGORY_TEST_TEXT = "Pain Reassessment";


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateUpdateDeleteAssessmentDocuments( )
        throws Exception
    {
        
        // Create AssessmentDocument
        String createRequestXml = createHaCreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID );
        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );
         
        // Update AssessmentDocument
        String updateRequestXml = createHaUpdateXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, recordIdentifier );
        updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml,"ASSESSMENT_DOCUMENT", "ASSESSMENT_DOCUMENT_ID" );

        // Logically Delete assessment document
        String logicalDeleteXml = createHAAssessmentDocumentDeleteXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, LOGICAL_DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, logicalDeleteXml, "ASSESSMENT_DOCUMENT", "ASSESSMENT_DOCUMENT_ID", true );
    
        //Delete assessment document
        String deleteXml = createHAAssessmentDocumentDeleteXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml, "ASSESSMENT_DOCUMENT", "ASSESSMENT_DOCUMENT_ID", false );
    }
    
    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateAssessmentDocumentsWithInvalidAssigningFacility( )
        throws Exception
    {
       
        String expectedExceptionMessage = "INVALID_ASSIGNING_FACILITY";
        
        // Create AssessmentDocument
        String createRequestXml = createHaInvalidPatientCreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID );
        Document clinicalDataDocument = createAndAssertExpectedExceptionMessage( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml, "fatalErrors", "exceptionMessage", expectedExceptionMessage );
        
    }
         


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testAssesmentDocumentListReadNoDates( )
        throws Exception
    {
        String[] hdrPatient1 = { ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, TEST_READ_PATIENTIDENTITY_HDR };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

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

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

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

        readAndAssertDomainData( filterXml );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testAssesmentDocumentListReadWithDates( )
        throws Exception
    {
        String[] hdrPatient1 = { ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, TEST_READ_PATIENTIDENTITY_HDR };
        String[][] patientIdentifiers = { hdrPatient1 };
        List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

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

        entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-17" );
        entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-17" );

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

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

        readAndAssertDomainData( filterXml );
    }
    
     @Test
     @Suite( groups = { "deprecatedtest" } )
     public void testAssesmentDocumentListReadWithCategory( )
         throws Exception
     {                 
         String[] hdrPatient1 = { ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, TEST_READ_PATIENTIDENTITY_HDR };
         String[][] patientIdentifiers = { hdrPatient1 };
         List<Map<String, String>> patients = getResolvedPatients( patientIdentifiers );

         Map<String, String> entryPointFilter = new HashMap<String, String>();
         entryPointFilter.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
         entryPointFilter.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
         
         entryPointFilter.put( FilterBuilder.START_DATE_KEY, "2012-03-17" );
         entryPointFilter.put( FilterBuilder.END_DATE_KEY, "2012-03-17" );

         List<Map<String, String>> entryPointFilterMaps = new ArrayList<Map<String, String>>();
         entryPointFilterMaps.add( entryPointFilter );
         
         Map<String,String> optionalQueryParameters = new HashMap<String,String>();
         optionalQueryParameters.put( CATEGORY_KEY, CATEGORY_TEST_TEXT );

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

         readAndAssertDomainData( filterXml );
     }
    
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateAssesmentDocumenReadWithDetailFilter( )
        throws Exception
    {
        String clientRequestInitiationTime = "2011-06-06T12:01:01Z";
        //create a new record for a detail read ...
        String createRequestXml = createHaCreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID );
        createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );

        //construct filter and read using detail filter/template
        Map<String, String> entryPointFilterMap = new HashMap<String, String>();
        entryPointFilterMap.put( FilterBuilder.DOMAIN_ENTRYPOINT_KEY, "AssessmentDocument" );
        entryPointFilterMap.put( FilterBuilder.RECORD_IDENTITY,recordIdentifier);
        entryPointFilterMap.put( FilterBuilder.QUERY_NAME_KEY, "queryName" );
        entryPointFilterMap.put( FilterBuilder.PATIENT_CENTRIC_KEY, "false" );
        
        String filterXml = FilterBuilder.buildDetailFilterWithRecordIdentifier( TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_FILTER, entryPointFilterMap, clientRequestInitiationTime );
      
        readAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_READ1_TEMPLATE, TemplateIdHelper.HEALTH_ADAPTER_ASSESSMENT_DOCUMENT_DETAIL_FILTER, filterXml );
        
        //Delete / cleanup assessment document
        String deleteXml = createHAAssessmentDocumentDeleteXml( TEST_CUD_PATIENTIDENTITY_HDR, "AssessmentDocuments", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, DELETE_RECORD_STATUS );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteXml, "ASSESSMENT_DOCUMENT", "ASSESSMENT_DOCUMENT_ID", false );
    }
    
    


    @SuppressWarnings( "unchecked" )
    protected Document readAndAssertDomainData( String filter )
        throws Exception
    {
        return readAndAssertDomainData(HA_READ_TEMPLATE_ID, FILTER_ID, filter);       
    }
    
    @SuppressWarnings( "unchecked" )
    protected Document readAndAssertDomainData( String templateId, String filterId, String filter )
        throws Exception
    {
        Document clinicalDataDocument = super.readAndAssertDomainData(templateId, filterId, filter );
          
        // Check for domain entry point elements
        List<Element> domainElements = clinicalDataDocument.selectNodes( READ_TEST_DOMAINENTRYPOINT_XPATH );
        assertTrue( domainElements.size() > 0 );
        return clinicalDataDocument;
    }
    
    protected String createHaCreateXml( String patientIdentifier, String entryPoint, String templateId )
    {
        return createHaXml( patientIdentifier,false, entryPoint, templateId, null );

    }


    protected String createHaUpdateXml( String patientIdentifier, String entryPoint, String templateId, String recordIdentifier )
    {
        return createHaXml( patientIdentifier, false, entryPoint, templateId, recordIdentifier );

    }
    
    protected String createHaInvalidPatientCreateXml( String patientIdentifier, String entryPoint, String templateId )
    {
        return createHaXml( patientIdentifier,true, entryPoint, templateId, null );

    }


    protected String createHaXml( String patientIdentifier, boolean invalidFacility, String entryPoint, String templateId, String recordIdentifier )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.AssessmentDocument );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAAssessmentDocumentBuilderFactory factory = new HAAssessmentDocumentBuilderFactory();

        HAAssessmentDocumentBuilder haAssessmentDocumentBuilder;
        if ( recordIdentifier != null )
        {
            haAssessmentDocumentBuilder = new HAAssessmentDocumentBuilder( recordIdentifier );
        }
        else
        {
            haAssessmentDocumentBuilder = new HAAssessmentDocumentBuilder();
        }
        factory.setAssessmentDocumentBuilder( haAssessmentDocumentBuilder );

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

        String assigningFacility = ASSIGNING_FACILITY_HDR;
        String assigningAuthority = ASSIGNINGAUTHORITY_HDR;
       
        if(invalidFacility){
            assigningFacility = INVALID_ASSIGNING_FACILITY_HDR;
            assigningAuthority= INVALID_ASSIGNINGAUTHORITY_HDR;
        
        }
        Element patient = null;
        if ( patientIdentifier == null )
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "patient");
        }
        else
        {
            patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "patient", patientIdentifier, assigningFacility, assigningAuthority );
        }

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

        return clinicalDataInsert.asXML();
    }


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

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HAAssessmentDocumentBuilderFactory factory = new HAAssessmentDocumentBuilderFactory();
        factory.setAssessmentDocumentBuilder( new HAAssessmentDocumentBuilder() );
        domainEntryPointsWrappersMap.put( "AssessmentDocument", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

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

        return clinicalDataInsert.asXML();
    }


    protected String getAssessmentDocumentEntryPointXpath( )
    {
        return "//AssessmentDocuments";
    }

}
