

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.request.TemplateRequestProcessor;
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.HACalendarEventBuilder;
import gov.va.med.cds.testharness.vhim400.builders.HACalendarEventBuilderFactory;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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 java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndCalendarEventTest
    extends
        AbstractHealthAdapterEndToEndTest
{
   
    @Before
    @Suite( groups = { "deprecatedtest" } )
    public void beforePatientContactLogJournalEntryTestClassSetUp( )
        throws Exception
    {
        requestProcessor = ( TemplateRequestProcessor )getRequestProcessor();
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "brokentest" } )
    public void testCreateReadAndDeletePatientCalendarEventSingle( )
        throws Exception
    {
        // Create calendar event
        String createRequestXml = createHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, "calendarEventTitle", null, 1 );
        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );

        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        assertTrue( recordIdentifierList.size() == 1 );
        String recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();

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

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

        String filterXml = createHAFilterXml( TEST_READ_PATIENTIDENTITY_HDR, null, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, null, null );

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

        List<Element> dataList = clinicalDataDocument.selectNodes( CALENDAR_EVENT_XPATH );
        assertTrue( dataList.size() > 0 );

        assigningAuthorityAndFacilityMap.clear();

        entryPointFilterMap.clear();
        entryPointFilterMap.put( "ID_1", "CalendarEvent" );

        filterXml = createHAFilterXml( TEST_READ_PATIENTIDENTITY_HDR, null, ASSIGNINGAUTHORITY_HDR, ASSIGNING_FACILITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_SINGLE_PATIENT_ALL_DATA_FILTER, START_DATE, getEndDateToday() );

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

        // logical delete calendar event
        String deleteRequestXML = deleteHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, true );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteRequestXML, "CALENDAR_EVENT", "CALENDAR_EVENT_ID", true );

        // Physical delete calendar event
        deleteRequestXML = deleteHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent", TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID,
                        recordIdentifier, false );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteRequestXML, "CALENDAR_EVENT", "CALENDAR_EVENT_ID",
                        false );
    }


    @SuppressWarnings( "unchecked" )
    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreateUpdateDeleteCalendarEventSingle( )
        throws Exception
    {

        // Create journal entry
        String createRequestXml = createHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, "calendarEventTitle", null, 1 );
        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, createRequestXml );

        List<Element> recordIdentifierList = clinicalDataDocument.selectNodes( RECORD_IDENTIFIER_IDENTITY_XPATH );
        assertTrue( recordIdentifierList.size() == 1 );
        String recordIdentifier = ( ( Element )recordIdentifierList.get( 0 ) ).getText();

        // Update journal entry
        String updateRequestXml = createHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, recordIdentifier, "calendarEventTitleUpdated", null, 1 );
        updateAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_UPDATE1_TEMPLATE_ID, updateRequestXml, "CALENDAR_EVENT", "CALENDAR_EVENT_ID" );

        // Physical delete journal entry
        String deleteRequestXML = deleteHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, recordIdentifier, false );
        deleteAndAssertDomainData( TemplateIdHelper.HEALTH_ADAPTER_DELETE1_TEMPLATE_ID, deleteRequestXML, "CALENDAR_EVENT", "CALENDAR_EVENT_ID",
                        false );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreatePatientCalendarEventInvalid( )
        throws Exception
    {
        // Create calendar event
        String createRequestXml = createHACreateXml( "", "CalendarEvent", TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null,
                        "calendarEventTitle", null, 1 );

        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestXml, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        new UniqueIdentifier().toString() );
        assertNotNull( clinicalDataDocument );

        Element exceptionElement = ( Element )clinicalDataDocument.selectSingleNode( FATAL_ERRORS_EXCEPTIONS_XPATH );
        assertNotNull( exceptionElement );
        assertTrue( exceptionElement.getText().endsWith( "SchemaValidationException" ) );
    }


    @Test
    @Suite( groups = { "deprecatedtest" } )
    public void testCreatePatientCalendarEventWithEmptyStartDate( )
        throws Exception
    {
        // Create calendar event
        String createRequestXml = createHACreateXml( TEST_CUD_PATIENTIDENTITY_HDR, "CalendarEvent",
                        TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID, null, "calendarEventTitle", "", 1 );

        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestXml, TemplateIdHelper.HEALTH_ADAPTER_CREATE1_TEMPLATE_ID,
                        new UniqueIdentifier().toString() );
        assertNotNull( clinicalDataDocument );

        Element exceptionElement = ( Element )clinicalDataDocument.selectSingleNode( FATAL_ERRORS_EXCEPTIONS_XPATH );
        assertNotNull( exceptionElement );
        assertTrue( exceptionElement.getText().endsWith( "SchemaValidationException" ) );
    }


    protected String createHAFilterXml( String patientIdentifier, List<Element> excludeIdentifiers, String assigningAuthority, String assigningFacility,
                    String entryPoint, String filterId, String startDate, String endDate )
    {
        Document filterDocument = FilterBuilder.buildEmptyFilterDocument();
        Element element = filterDocument.getRootElement();
        element.add( FilterBuilder.createFilterId( "filterId", filterId ) );
        element.add( FilterBuilder.createClientName( "clientName", "testClientName" ) );
        element.add( FilterBuilder.createClientRequestInitiationTime( "clientRequestInitiationTime",
                        DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format( new Date() ) ) );
        element.add( FilterBuilder.createPatientWithEdipi( "patients", patientIdentifier, excludeIdentifiers, assigningAuthority, assigningFacility ) );
        element.add( FilterBuilder.createMHAEntryFilterWithAdditionalParametersNoEndDate( "entryPointFilter", entryPoint, startDate, endDate, "ID_1" ) );
        element.addAttribute( "vhimVersion", "Vhim_4_00" );
        return element.asXML();
    }


    protected String createHACreateXml( String patientIdentifier, String entryPoint, String templateId, String recordIdentifier, String title,
                    String calendarEventStartDate, int count )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( templateId, DomainEntryPoint.CalendarEvent );
        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

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

        if ( calendarEventStartDate != null )
        {
            factory.setCalendarEventBuilder( new HACalendarEventBuilder( recordIdentifier, title, calendarEventStartDate ) );
        }
        else
        {
            factory.setCalendarEventBuilder( new HACalendarEventBuilder( recordIdentifier, title ) );
        }

        domainEntryPointsWrappersMap.put( "CalendarEvent", 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, count, patient );
        return vdmClinicalDataInsert.asXML();
    }


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

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        HACalendarEventBuilderFactory factory = new HACalendarEventBuilderFactory();
        factory.setCalendarEventBuilder( new HACalendarEventBuilder( recordIdentifier ) );
        domainEntryPointsWrappersMap.put( "CalendarEvent", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

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

        String recordStatus = "0";
        if ( logicalDelete )
            recordStatus = "1";

        Document vdmClinicalDataInsert = clinicalDataBuilder.deleteClinicalData( domainEntryPointsMap.get( templateId ), templateId, patient,
                        recordIdentifier, recordStatus );
        return vdmClinicalDataInsert.asXML();
    }


    private String getEndDateToday( )
    {
        Date today = new Date();
        SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd" );
        String parsed = null;

        try
        {
            parsed = format.format( today );
        }
        catch ( Exception e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return parsed.toString();
    }
}
