

package gov.va.med.cds.integration;


import gov.va.med.cds.junit.runners.SuiteAwareRunner;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.request.ReadResponseInterface;
import gov.va.med.cds.request.ResponseInterface;
import gov.va.med.cds.testharness.xml.XmlCompareException;
import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import org.dom4j.Document;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.xml.sax.SAXException;


/**
 * 
 * This initiates all tests through the outermost client pojo (ClinicalDataServiceSynchronous). 
 * This has the vhim version agnostic functionality that is common to the vhim version specific subclasses.
 * It will generate a vdm record and save it off to the DB. Next, it will read the same record back through HDR2 and Hx. Merge
 * will be tested through different scenios - Merge and Non-Merge.
 * TODO: Functionality not covered that is not specific to this test:
 *  - The return xml content of deleteClinicalData is not checked here and needs to be checked in the Delete unit test level 
 *  - The merged/non-merged record content is not checked here and need to be done in ReadRequest unit test level.
 */
@RunWith( SuiteAwareRunner.class )
public abstract class AbstractEndToEndCRUADAutoWiredMergeTest
    extends
        AbstractEndToEndTest
{

    /**
     * Tests the Non-Merge scenario. Creates a hdr record with different Identity than the one existing in Hx 
     * and returns two records from HDR2 database. 
     * @throws SAXException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws XmlCompareException
     */
    @Test
    @Suite( groups = { "brokentest" } )
    public void testIntoleranceConditionCreateReadNoMergeDelete( )
        throws SAXException,
            IOException,
            ParserConfigurationException,
            XmlCompareException
    {
        // Existing patient from Hx
        String hxLocalPatientIdEntityIdentifier = "129";
        String hxLocalPatientIdAssigningFacUniversalId = "613";

        // hdr cleanup - deletes any existing non-hx IC records
        String readResult = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );
        deleteNonHxAllergy( readResult );

        readResult = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );
        int numberOfDomainRecords = getDomainRecordCount( readResult );
        assertEquals( numberOfDomainRecords, 1 ); // we know that Hx has only one record

        // Create the IC record in hdr by changing the Hx record identity
        createAllergyWithDifferentIdentity();

        // read the allergies from hdr and hx
        readResult = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );

        // Check that there are 2 IntoleranceCondition records (one from Hx and other from Hdr)
        numberOfDomainRecords = getDomainRecordCount( readResult );
        assertEquals( numberOfDomainRecords, 2 );
    }


    /**
     * Tests the Merge scenario. Creates a hdr record with same Identity as that of the one existing in Hx; but has a different value in Non-id field 
     * to check the Merge functionality and expects a single merged record returned from th HDR2 database. 
     * @throws SAXException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws XmlCompareException
     */
    @Test
    @Suite( groups = { "brokentest" } )
    public void testIntoleranceConditionCreateReadMergeDelete( )
        throws SAXException,
            IOException,
            ParserConfigurationException,
            XmlCompareException
    {
        String hxLocalPatientIdEntityIdentifier = "129";
        String hxLocalPatientIdAssigningFacUniversalId = "613";

        // Read the IntoleranceCondition records from Historical for the given patient
        String readResultFromHx = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );
        String hxICDescription = getIntoleranceConditionAuthorComment( readResultFromHx );
        // hdr cleanup - deletes any existing non-hx IC records
        deleteNonHxAllergy( readResultFromHx );

        readResultFromHx = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );
        int numberOfDomainRecords = getDomainRecordCount( readResultFromHx );
        assertEquals( numberOfDomainRecords, 1 ); // we know that Hx has only one record

        // Create the IC record in Hdr by changing the Hx record identity
        createAllergyWithSameIdentity();

        // read the allergies from Hdr and Hx
        String readResult = readAllergyData( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );

        // Check that there is only one Merged IntoleranceCondition record
        numberOfDomainRecords = getDomainRecordCount( readResult );
        assertEquals( numberOfDomainRecords, 1 );

        String hdrICDescription = getIntoleranceConditionAuthorComment( readResult );
        assertNotSame( hdrICDescription, hxICDescription ); // ensure that the recently modified Description field value is returned from Hdr
    }


    protected abstract int getDomainRecordCount( String readResultFromHx );


    protected abstract void checkForNoErrorsInXml( String createResult );


    protected abstract String getAllergyFilterId( );


    protected abstract String getAllergyFilterWithOneResolvedId( String hxLocalPatientIdEntityIdentifier,
                    String hxLocalPatientIdAssigningFacUniversalId );


    protected abstract String getAllergyReadTemplateId( );


    protected abstract String getAllergyCreateTemplateId( );


    protected abstract String getAllergyDeleteTemplateId( );


    protected abstract String getIntoleranceConditionAuthorComment( String readResultFromHx );


    protected abstract String populateTemplateMetaDataOfClinicalDataRecord( String templateId, String readResultFromHx, int recordNumber );


    protected abstract String createAllergyXmlDifferentIdentity( );


    protected abstract String createAllergyXmlWithSameIdentity( );


    /**
     * Reads the IntoleranceCondition records based on the Identity 
     * @param hxLocalPatientIdEntityIdentifier
     * @param hxLocalPatientIdAssigningFacUniversalId
     * @return Read result xml
     */
    private String readAllergyData( String hxLocalPatientIdEntityIdentifier, String hxLocalPatientIdAssigningFacUniversalId )
    {
        String allergyReadTemplateId = getAllergyReadTemplateId();
        String allergyFilter = getAllergyFilterWithOneResolvedId( hxLocalPatientIdEntityIdentifier, hxLocalPatientIdAssigningFacUniversalId );
        String allergyFilterId = getAllergyFilterId();
        Document readResultFromHx = getRequestProcessor().readClinicalData( allergyReadTemplateId, allergyFilter, allergyFilterId,
                        new UniqueIdentifier().toString() );
        
        checkForNoErrorsInXml( readResultFromHx.asXML());

        return readResultFromHx.asXML();
    }


    /**
     * Deletes the IntoleranceCondition data.
     * @param readResultFromHx
     */
    private void deleteNonHxAllergy( String readResultFromHx )
    {
        String allergyDeleteTemplateId = getAllergyDeleteTemplateId();
        int numberOfDomainRecords = getDomainRecordCount( readResultFromHx );
        while ( numberOfDomainRecords-- > 0 )
        {
            String deleteXmlRequest = populateTemplateMetaDataOfClinicalDataRecord( allergyDeleteTemplateId, readResultFromHx, numberOfDomainRecords );
            getRequestProcessor().deleteClinicalData( deleteXmlRequest, allergyDeleteTemplateId, new UniqueIdentifier().toString() );
        }
    }


    /**
     * Creates an IntoleranceCondition with a different identity and checks for no errors in create result xml.
     *
     */
    private void createAllergyWithDifferentIdentity( )
    {
        String createXmlRequest = createAllergyXmlDifferentIdentity();
        String allergyCreateTemplateId = getAllergyCreateTemplateId();
        Document createResult = getRequestProcessor().createClinicalData( createXmlRequest, allergyCreateTemplateId,
                        new UniqueIdentifier().toString() );
        checkForNoErrorsInXml( createResult.asXML() );
    }


    /**
     * Creates an IntoleranceCondition with a same identity and checks for no errors in create result xml.
     *
     */
    private void createAllergyWithSameIdentity( )
    {
        String createXmlRequest = createAllergyXmlWithSameIdentity();
        String allergyCreateTemplateId = getAllergyCreateTemplateId();
        Document createResult = getRequestProcessor().createClinicalData( createXmlRequest, allergyCreateTemplateId,
                        new UniqueIdentifier().toString() );
        checkForNoErrorsInXml( createResult.asXML() );
    }

}
