

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


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

import gov.va.med.cds.clinicaldata.DomainEntryPoint;
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.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.LabBuilder;
import gov.va.med.cds.testharness.vhim400.builders.LabBuilderFactory;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

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;

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


@RunWith( SuiteAwareSpringRunner.class )
public class EndToEndCreateLabTest
    extends
        AbstractEndToEndTest
{
    private static final String PATIENTIDENTITY_HDR = "testId5555";
    private static final String ASSIGNING_FACILITY_HDR = "200CH";
    private static final String ASSIGNING_AUTHORITY_HDR = "USDOD";

    private static final String REQUEST_ID_XPATH = "/clinicaldata:ClinicalData/requestId";
    private static final String ERROR_SECTION_ERRORS_XPATH = "//clinicaldata:ClinicalData/errorSection/errors";
    private static final String ERROR_SECTION_WARNINGS_XPATH = "//clinicaldata:ClinicalData/errorSection/warnings";
    private static final String ERROR_SECTION_FATAL_ERRORS_XPATH = "//clinicaldata:ClinicalData/errorSection/fatalErrors";

    @Autowired
    private JdbcTemplate hdrJdbcTemplate;

    private TemplateRequestProcessor requestProcessor;


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


    @Test
    @Suite( groups = { "checkintest" } )
    public void testLabTestPromiseCreate( )
        throws Exception
    {
        // Clean up any old test data
        doDelete( PATIENTIDENTITY_HDR );

        String requestId = new UniqueIdentifier().toString();
        Document createRequestDoc = createWriteRequestXml();
        String createRequestXml = createRequestDoc.asXML();

        Document clinicalDataDocument = createAndAssertDomainData( TemplateIdHelper.LAB_CREATEORUPDATE_TEMPLATE_ID, createRequestXml, requestId );
        assertNotNull( clinicalDataDocument );

        // Verify requestId
        String requestIdFromResponse = clinicalDataDocument.selectSingleNode( REQUEST_ID_XPATH ).getText();
        assertTrue( requestId.equals( requestIdFromResponse ) );

        // verify written lab data using SQL 'select' 
        verifyLabRead( PATIENTIDENTITY_HDR );

        // Clean up
        //doDelete( PATIENTIDENTITY_HDR );
    }


    private Document createWriteRequestXml( )
    {
        Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
        domainEntryPointsMap.put( TemplateIdHelper.LAB_CREATEORUPDATE_TEMPLATE_ID, DomainEntryPoint.LabTestPromise );

        ClinicalDataBuilder clinicalDataBuilder = new ClinicalDataBuilder();
        clinicalDataBuilder.setDomainEntryPointsMap( domainEntryPointsMap );

        Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
        LabBuilderFactory factory = new LabBuilderFactory();
        factory.setLabBuilder( new LabBuilder() );
        domainEntryPointsWrappersMap.put( "LabTestPromise", factory );
        clinicalDataBuilder.setDomainEntryPointsWrappersMap( domainEntryPointsWrappersMap );

        Element patient = BaseDatatypesBuilder.createHL72PersonIdentifier( "patient", PATIENTIDENTITY_HDR, ASSIGNING_FACILITY_HDR,
                        ASSIGNING_AUTHORITY_HDR );
        Document vdmClinicalDataInsert = clinicalDataBuilder.createClinicalData( TemplateIdHelper.LAB_CREATEORUPDATE_TEMPLATE_ID, 1, patient );

        return vdmClinicalDataInsert;
    }


    @SuppressWarnings( "unchecked" )
    private Document createAndAssertDomainData( String templateId, String createRequestXml, String requestId )
        throws Exception
    {
        requestProcessor.setValidateReadResponseXML( true );
        Document clinicalDataDocument = requestProcessor.createClinicalData( createRequestXml, templateId, requestId );
        assertNotNull( clinicalDataDocument );

        // Check for an empty error section
        List<Element> errorSections = clinicalDataDocument.selectNodes( XPATH_ERRORSECTION );
        assertTrue( errorSections.size() == 1 );
        Element errorSection = errorSections.get( 0 );
        assertTrue( errorSection.content().size() == 0 );

        List<Element> errors = clinicalDataDocument.selectNodes( ERROR_SECTION_ERRORS_XPATH );
        assertTrue( errors.size() == 0 );

        List<Element> warnings = clinicalDataDocument.selectNodes( ERROR_SECTION_WARNINGS_XPATH );
        assertTrue( warnings.size() == 0 );

        List<Element> fatalErrors = clinicalDataDocument.selectNodes( ERROR_SECTION_FATAL_ERRORS_XPATH );
        assertTrue( fatalErrors.size() == 0 );

        return clinicalDataDocument;
    }


    private void verifyLabRead( String patientId )
    {
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM CHEMRSLT_COMMENT_V WHERE CHEMRSLT_COMMENT_EVENT_ID IN( SELECT CHEMRSLT_COMMENT_EVENT_ID FROM CHEMRSLT_COMMENT_EVENT_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN ( SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "'))))", Integer.class ) == 16 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM LAB_OBSERVATION_METHOD_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "')))", Integer.class ) == 8 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM CHEMRSLT_COMMENT_EVENT_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "')))", Integer.class ) == 8 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "'))", Integer.class ) == 4 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM LAB_COMMENT_V WHERE LAB_COMMENT_EVENT_ID IN (SELECT  LAB_COMMENT_EVENT_ID FROM LAB_COMMENT_EVENT_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "'))", Integer.class ) == 4 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM LAB_COMMENT_EVENT_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY ='"
                                        + patientId + "')", Integer.class ) == 2 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "')", Integer.class ) == 2 );
        assertTrue( hdrJdbcTemplate
                        .queryForObject( "SELECT COUNT(1) FROM LAB_PATIENT_VISIT_V WHERE LAB_PATIENT_VISIT_ID = (SELECT LAB_PATIENT_VISIT_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                                        + patientId + "')", Integer.class ) == 1 );
        assertTrue( hdrJdbcTemplate.queryForObject( "SELECT COUNT(1) FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '" + patientId + "'", Integer.class ) == 1 );
    }


    private void doDelete( String patientId )
    {
        List<String> labPatientVisitIds = null;
        int recordExists = 0;

        recordExists = hdrJdbcTemplate.queryForObject( "SELECT COUNT(1) FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '" + patientId + "'", Integer.class );

        if ( recordExists > 0 )
        {
            labPatientVisitIds = hdrJdbcTemplate.queryForList( "SELECT LAB_PATIENT_VISIT_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '" + patientId + "'", String.class );

            hdrJdbcTemplate.update( "DELETE FROM CHEMRSLT_COMMENT_V WHERE CHEMRSLT_COMMENT_EVENT_ID IN( SELECT CHEMRSLT_COMMENT_EVENT_ID FROM CHEMRSLT_COMMENT_EVENT_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN ( SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "'))))" );
            hdrJdbcTemplate.update( "DELETE FROM LAB_OBSERVATION_METHOD_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "')))" );
            hdrJdbcTemplate.update( "DELETE FROM CHEMRSLT_COMMENT_EVENT_V WHERE CHEMISTRY_RESULT_ID IN ( SELECT CHEMISTRY_RESULT_ID FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "')))" );
            hdrJdbcTemplate.update( "DELETE FROM CHEMISTRY_RESULT_V WHERE LAB_TEST_ID IN ( SELECT  LAB_TEST_ID FROM LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "'))" );
            hdrJdbcTemplate.update( "DELETE FROM LAB_COMMENT_V WHERE LAB_COMMENT_EVENT_ID IN (SELECT  LAB_COMMENT_EVENT_ID FROM LAB_COMMENT_EVENT_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "'))" );
            hdrJdbcTemplate.update( "DELETE FROM LAB_COMMENT_EVENT_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY ='"
                            + patientId + "')" );
            hdrJdbcTemplate.update( "DELETE LAB_TEST_V WHERE LAB_TEST_PRM_ID IN (SELECT LAB_TEST_PRM_ID FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '"
                            + patientId + "')" );
            hdrJdbcTemplate.update( "DELETE FROM LAB_TEST_PRM_V WHERE PATIENT_IDENTITY = '" + patientId + "'" );

            if ( null != labPatientVisitIds && labPatientVisitIds.size() > 0 )
            {
            	for ( String labPatientVisitId : labPatientVisitIds ) 
            	{
            		hdrJdbcTemplate.update( "DELETE FROM LAB_PATIENT_VISIT_V WHERE LAB_PATIENT_VISIT_ID = '" + labPatientVisitId + "'" );
            	}
            }
        }
    }
}
