

package gov.va.med.cds.tools.cleanup.errorq;


import gov.va.med.cds.junit.runners.BeforeTestsOnce;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.testharness.AbstractBaseTest;
import gov.va.med.cds.util.StreamUtil;
import gov.va.med.hds.hdr.busobj.patient.Patient;
import gov.va.med.hds.hdr.busobj.patient.PatientBuilderException;
import gov.va.med.hds.hdr.busobj.patient.PatientIdentifier;
import gov.va.med.hds.hdr.busobj.patient.XMLPatientBuilder;

import java.io.IOException;
import java.util.Collections;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.DocumentException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;


@RunWith( SuiteAwareSpringRunner.class )
@ContextConfiguration( locations = { "classpath:gov/va/med/cds/tools/cleanup/errorq/errorQCleanUpContext.xml",
                "classpath:gov/va/med/cds/tools/cleanup/errorq/test-errorQCleanUpContext.xml" } )
public class PsimGraphMessageHandlerTest
    extends
        AbstractBaseTest
{
    private Log logger = LogFactory.getLog( PsimGraphMessageHandlerTest.class );

    private static PsimGraphMessageHandlerData vaPatientNamedParameter = new PsimGraphMessageHandlerData();
    private static PsimGraphMessageHandlerData dodPatientNamedParameter = new PsimGraphMessageHandlerData();
    private ResourceLoader resourceLoader = new DefaultResourceLoader();
    private PsimGraphMessageHandler psimGraphMessageHandler;
    private QueueSender vaPatientCorrelationQueueSender;
    private QueueSender dodPatientCorrelationQueueSender;
    private NamedParameterJdbcTemplate dodJdbcTemplate;
    private NamedParameterJdbcTemplate vaJdbcTemplate;
    private NamedParameterJdbcTemplate xJdbcTemplate;
    private static Patient vaPatient;
    private static Patient dodPatient;
    private Resource resource;

    private static String selectSql = "SELECT COUNT (*) FROM domain_id WHERE domain = :localIdentifierDomain AND domain_id = :localIdentifier AND STATUS = :status";
    private static String updateSql = "UPDATE domain_id SET STATUS = :status WHERE domain = :localIdentifierDomain AND domain_id = :localIdentifier";
    private static String deleteSql = "DELETE from domain_id";
    private static String deleteSqlImsHl7MessageLog = "DELETE from Ims_hl7_Message_log";
    private static String deleteSqlImshl7MessageStatus = "DELETE from Ims_hl7_Message_Status";
    private static String deleteSqlMpi = "DELETE from mpi";


    @javax.annotation.Resource
    public void setVaPatientCorrelationQueueSender( QueueSender vaPatientCorrelationQueueSender )
    {
        this.vaPatientCorrelationQueueSender = vaPatientCorrelationQueueSender;
    }


    @javax.annotation.Resource
    public void setDodPatientCorrelationQueueSender( QueueSender dodPatientCorrelationQueueSender )
    {
        this.dodPatientCorrelationQueueSender = dodPatientCorrelationQueueSender;
    }


    @javax.annotation.Resource
    public void setPsimGraphMessageHandler( PsimGraphMessageHandler psimGraphMessageHandler )
    {
        this.psimGraphMessageHandler = psimGraphMessageHandler;
    }


    @javax.annotation.Resource
    public void setVaJdbcTemplate( NamedParameterJdbcTemplate vaJdbcTemplate )
    {
        this.vaJdbcTemplate = vaJdbcTemplate;
    }


    @javax.annotation.Resource
    public void setDodJdbcTemplate( NamedParameterJdbcTemplate dodJdbcTemplate )
    {
        this.dodJdbcTemplate = dodJdbcTemplate;
    }


    @javax.annotation.Resource
    public void setxJdbcTemplate( NamedParameterJdbcTemplate xJdbcTemplate )
    {
        this.xJdbcTemplate = xJdbcTemplate;
    }


    private void cleanDb( )
    {
        vaJdbcTemplate.update( deleteSql, Collections.EMPTY_MAP );
        vaJdbcTemplate.update( deleteSqlImsHl7MessageLog, Collections.EMPTY_MAP );
        vaJdbcTemplate.update( deleteSqlImshl7MessageStatus, Collections.EMPTY_MAP );
        vaJdbcTemplate.update( deleteSqlMpi, Collections.EMPTY_MAP );
        dodJdbcTemplate.update( deleteSql, Collections.EMPTY_MAP );
        dodJdbcTemplate.update( deleteSqlImsHl7MessageLog, Collections.EMPTY_MAP );
        dodJdbcTemplate.update( deleteSqlImshl7MessageStatus, Collections.EMPTY_MAP );
        dodJdbcTemplate.update( deleteSqlMpi, Collections.EMPTY_MAP );
        xJdbcTemplate.update( deleteSql, Collections.EMPTY_MAP );
        xJdbcTemplate.update( deleteSqlMpi, Collections.EMPTY_MAP );
    }


    @BeforeTestsOnce
    @Suite( groups = { "checkintest" } )
    public void setUp( )
        throws DocumentException,
            IOException,
            PatientBuilderException,
            InterruptedException
    {
        cleanDb();

        vaPatient = XMLPatientBuilder.buildPaitient( getPatientGraphAsString( "psimGraphVa.xml" ) );
        dodPatient = XMLPatientBuilder.buildPaitient( getPatientGraphAsString( "psimGraphDod.xml" ) );

        vaPatientNamedParameter.setLocalIdentifier( getLocalIdentifier( vaPatient ).getId() );
        vaPatientNamedParameter.setLocalIdentifierDomain( getLocalIdentifier( vaPatient ).getDomain() );
        vaPatientNamedParameter.setStatus( "C" );

        vaPatientNamedParameter.setNationalIdentifier( getNationalIdentifier( vaPatient ).getId() );
        vaPatientNamedParameter.setNationalIdentifier( getNationalIdentifier( vaPatient ).getDomain() );

        dodPatientNamedParameter.setLocalIdentifier( getLocalIdentifier( dodPatient ).getId() );
        dodPatientNamedParameter.setLocalIdentifierDomain( getLocalIdentifier( dodPatient ).getDomain() );
        dodPatientNamedParameter.setStatus( "C" );

        dodPatientNamedParameter.setNationalIdentifier( getNationalIdentifier( dodPatient ).getId() );
        dodPatientNamedParameter.setNationalIdentifier( getNationalIdentifier( dodPatient ).getDomain() );

        vaPatientCorrelationQueueSender.sendMessage( vaPatient.toString() );
        dodPatientCorrelationQueueSender.sendMessage( dodPatient.toString() );
        Thread.sleep( 5000 );
    }


    @Test
    @Suite( order = 1, groups = { "checkintest" } )
    public void testGraphVaPatientExists( )
        throws IOException,
            DocumentException,
            InterruptedException,
            PatientBuilderException
    {
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphVa.xml" ) );
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphVaLocalIdentifier.xml" ) );
        Thread.sleep( 5000 );
        Assert.assertEquals( 1, (int)vaJdbcTemplate.queryForObject( selectSql, new BeanPropertySqlParameterSource( vaPatientNamedParameter ), Integer.class  ));
    }


    @Test
    @Suite( order = 2, groups = { "checkintest" } )
    public void testGraphDodPatientExists( )
        throws IOException,
            DocumentException,
            InterruptedException,
            PatientBuilderException
    {
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphDod.xml" ) );
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphDodLocalIdentifier.xml" ) );
        Thread.sleep( 5000 );
        Assert.assertEquals( 1, (int)dodJdbcTemplate.queryForObject( selectSql, new BeanPropertySqlParameterSource( dodPatientNamedParameter ), Integer.class  ) );
    }


    @Test
    @Suite( order = 3, groups = { "checkintest" } )
    public void testGraphVaPatientWithOnlyLocalIdentifierUnCorrelatedAndExists( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        vaPatientNamedParameter.setStatus( "U" );
        vaJdbcTemplate.update( updateSql, new BeanPropertySqlParameterSource( vaPatientNamedParameter ) );
        vaPatientNamedParameter.setStatus( "C" );
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphVaLocalIdentifier.xml" ) );
    }


    @Test
    @Suite( order = 4, groups = { "checkintest" } )
    public void testGraphDodPatientWithOnlyLocalIdentifierUnCorrelatedAndExists( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        dodPatientNamedParameter.setStatus( "U" );
        dodJdbcTemplate.update( updateSql, new BeanPropertySqlParameterSource( dodPatientNamedParameter ) );
        dodPatientNamedParameter.setStatus( "C" );
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphDodLocalIdentifier.xml" ) );
    }


    @Test
    @Suite( order = 5, groups = { "checkintest" } )
    public void testGraphVaPatientDoesNotExist( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        cleanDb();
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphVa.xml" ) );
        Thread.sleep( 5000 );
        Assert.assertEquals( 1, (int)vaJdbcTemplate.queryForObject( selectSql, new BeanPropertySqlParameterSource( vaPatientNamedParameter ), Integer.class  ) );
    }


    @Test
    @Suite( order = 6, groups = { "checkintest" } )
    public void testGraphDodPatientDoesNotExist( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        cleanDb();
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphDod.xml" ) );
        Thread.sleep( 5000 );
        Assert.assertEquals( 1, (int)dodJdbcTemplate.queryForObject( selectSql, new BeanPropertySqlParameterSource( dodPatientNamedParameter ), Integer.class  ) );
    }


    @Test
    @Suite( order = 7, groups = { "checkintest" } )
    public void testGraphVaPatientWithLocalIdentifierOnlyAndDoesNotExist( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        cleanDb();
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphVaLocalIdentifier.xml" ) );
    }


    // The Patient does not exist in MPI
    @Test( expected = RuntimeException.class )
    @Suite( order = 8, groups = { "checkintest" } )
    public void testGraphDodPatientWithLocalIdentiferOnlyAndDoesNotExist( )
        throws DocumentException,
            IOException,
            InterruptedException,
            PatientBuilderException
    {
        cleanDb();
        psimGraphMessageHandler.handleMessage( getPatientGraphAsString( "psimGraphDodLocalIdentifier.xml" ) );
    }


    private String getPatientGraphAsString( String pathToGraphXml )
        throws IOException
    {
        resource = resourceLoader.getResource( "classpath:gov/va/med/cds/tools/cleanup/errorq/" + pathToGraphXml );

        if ( logger.isDebugEnabled() )
        {
            logger.debug( StreamUtil.resourceToString( resource ) );
        }

        return StreamUtil.resourceToString( resource );

    }


    private PatientIdentifier getLocalIdentifier( Patient patient )
    {
        return patient.getFirstIdentifier( Patient.TYPEID_LOCAL );

    }


    private PatientIdentifier getNationalIdentifier( Patient patient )
    {
        return patient.getFirstIdentifier( Patient.TYPEID_NATIONAL );
    }
}
