/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.dmg.builders;

import java.security.MessageDigest;

import org.joda.time.DateTime;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import be.ehealth.business.common.domain.Patient;
import be.ehealth.business.mycarenetcommons.builders.BlobBuilder;
import be.ehealth.business.mycarenetcommons.builders.BlobBuilderFactory;
import be.ehealth.business.mycarenetcommons.domain.Blob;
import be.ehealth.business.mycarenetcommons.exception.InvalidBlobContentConnectorException;
import be.ehealth.businessconnector.dmg.domain.TestAction;
import be.ehealth.businessconnector.dmg.exception.DmgBusinessConnectorException;
import be.ehealth.technicalconnector.enumeration.Charset;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.globalmedicalfile.core.v1.RequestType;
import be.fgov.ehealth.globalmedicalfile.protocol.v1.SendRequestType;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;


/**
 * Unit Tests.
 * 
 * @author EHP
 * 
 */

public class CommonBuilderIntegrationTest {

    private static final Logger LOG = LoggerFactory.getLogger(CommonBuilderIntegrationTest.class);

    @BeforeClass
    public static void init() throws Exception {
        SessionInitializer.init("/be.ehealth.businessconnector.dmg.test.properties");
    }

    @AfterClass
    public static void tearDown() throws Exception {
        Session.getInstance().unloadSession();
    }

    @Test
    public void consultOK() throws Exception {
        LOG.debug("Start of the Consult test ok");
        generateBasicTest(TestAction.consult, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test
    public void consultOKNonDeflate() throws Exception {
        LOG.debug("Start of the Consult test ok");
        generateBasicTestWithoutHash(TestAction.consult, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = DmgBusinessConnectorException.class)
    public void consultERRORInputRefNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.consult, null, "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = DmgBusinessConnectorException.class)
    public void consultERRORRefDateNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.consult, "1", "301", "4654454545678", "67032004773", null, ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = InvalidBlobContentConnectorException.class)
    public void consultERRORBlobContentNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.consult, "1", "301", "4654454545678", "67032004773", new DateTime(), null, "a1", "String");
    }

    @Test(expected = InvalidBlobContentConnectorException.class)
    public void consultERRORBlobContentTypeNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.consult, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", null);
    }

    // TODO prc DmgBusinessConnectorException >< InvalidBlobContentConnectorException
    @Test(expected = DmgBusinessConnectorException.class)
    public void consultERRORBlobIdNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.consult, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), null, "String");
    }

    @Test
    public void notifyOK() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = DmgBusinessConnectorException.class)
    public void notifyERRORInputRefNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, null, "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = DmgBusinessConnectorException.class)
    public void notifyERRORRefDateNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, "1", "301", "4654454545678", "67032004773", null, ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", "String");
    }

    @Test(expected = InvalidBlobContentConnectorException.class)
    public void notifyERRORBlobContentNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, "1", "301", "4654454545678", "67032004773", new DateTime(), null, "a1", "String");
    }

    @Test(expected = InvalidBlobContentConnectorException.class)
    public void notifyERRORBlobContentTypeNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), "a1", null);
    }

    // TODO prc DmgBusinessConnectorException >< InvalidBlobContentConnectorException
    @Test(expected = DmgBusinessConnectorException.class)
    public void notifyERRORBlobIdNull() throws Exception {
        LOG.debug("Start of the Notify test ok");
        generateBasicTest(TestAction.notify, "1", "301", "4654454545678", "67032004773", new DateTime(), ConnectorIOUtils.toBytes("message", Charset.UTF_8), null, "String");
    }


    public SendRequestType generateBasicTest(TestAction action, String inputRef, String mutuality, String regnrwithmut, String inss, DateTime dateref, byte[] blobcontent, String blobid, String blobcontenttype) throws Exception {

        LOG.debug("Creation of Object DmgReferences...");
        String ref = inputRef;

        LOG.debug("Creation of Object PatientInfo...");
        Patient pI = new Patient();
        pI.setMutuality(mutuality);
        pI.setRegNrWithMut(regnrwithmut);
        pI.setInss(inss);

        LOG.debug("Creation of Object Blob...");
        BlobBuilder bbuilder = BlobBuilderFactory.getBlobBuilder("dmg");
        Blob blob = bbuilder.build(blobcontent, "deflate", blobid, blobcontenttype);
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        byte[] buffhash = blobcontent;
        md.update(buffhash);
        blob.setHashValue(md.digest());

        RequestObjectBuilder builder = RequestObjectBuilderFactory.getRequestObjectBuilder();
        SendRequestType result = null;
        switch (action.getValue()) {
            case 1:
                LOG.debug("Consult request sended");
                result = builder.buildSendConsultRequest(true, ref, pI, dateref, blob, null);

                LOG.debug("Check on XadesT ...");
                Assert.assertNull(result.getXadesT());

                break;
            case 0:
                LOG.debug("Notify request sended");
                result = builder.buildSendNotifyRequest(true, ref, pI, dateref, blob, null);

                LOG.debug("Check on XadesT ...");
                Assert.assertNotNull(result.getXadesT());

                break;
        }

        // Check all values
        LOG.debug("Check on CommonInput ...");
        Assert.assertEquals("inputreference incorrect", ref, result.getCommonInput().getInputReference());
        Assert.assertNotNull(result.getCommonInput().getOrigin());

        RequestType rT = new RequestType();
        rT.setIsTest(true);
        Assert.assertEquals("istest incorrect", rT.isIsTest(), result.getCommonInput().getRequest().isIsTest());

        LOG.debug("Check on Routing ...");
        Assert.assertEquals("Dateref incorrect", dateref.toDateMidnight(), result.getRouting().getReferenceDate().toDateMidnight());
        // TODO prc null >< mutuality ?
        Assert.assertEquals("Mut incorrect", mutuality, result.getRouting().getCareReceiver().getMutuality());
        Assert.assertEquals("RegNrWithMut incorrect", regnrwithmut, result.getRouting().getCareReceiver().getRegNrWithMut());
        Assert.assertEquals("Ssin incorrect", pI.getInss(), result.getRouting().getCareReceiver().getSsin());
        Assert.assertNull(result.getRouting().getPeriod());

        LOG.debug("Check on Detail ...");
        Assert.assertEquals("Blob id type incorrect", blobid, result.getDetail().getId());
        Assert.assertEquals("Blob content type incorrect", blobcontenttype, result.getDetail().getContentType());
        Assert.assertEquals("Blob content encodingincorrect", "deflate", result.getDetail().getContentEncoding());

        LOG.debug("Check on Detail content  ...");
        Blob resultBlob = new Blob();
        resultBlob.setContent(result.getDetail().getValue());
        resultBlob.setContentEncoding("deflate");
        resultBlob.setHashValue(blob.getHashValue());
        Assert.assertEquals("Blob content incorrect", ConnectorIOUtils.toString(blobcontent, Charset.UTF_8), ConnectorIOUtils.toString(bbuilder.checkAndRetrieveContent(resultBlob), Charset.UTF_8));
        Assert.assertEquals("Blob content hashValue incorrect", blob.getHashValue(), result.getDetail().getHashValue());

        return result;
    }

    public SendRequestType generateBasicTestWithoutHash(TestAction action, String inputRef, String mutuality, String regnrwithmut, String inss, DateTime dateref, byte[] blobcontent, String blobid, String blobcontenttype) throws Exception {

        LOG.debug("Creation of Object DmgReferences...");
        String ref = inputRef;

        LOG.debug("Creation of Object PatientInfo...");
        Patient pI = new Patient();
        pI.setMutuality(mutuality);
        pI.setRegNrWithMut(regnrwithmut);
        pI.setInss(inss);

        LOG.debug("Creation of Object Blob...");
        BlobBuilder bbuilder = BlobBuilderFactory.getBlobBuilder("dmg");
        Blob blob = bbuilder.build(blobcontent, "none", blobid, blobcontenttype);

        RequestObjectBuilder builder = RequestObjectBuilderFactory.getRequestObjectBuilder();
        SendRequestType result = null;
        switch (action.getValue()) {
            case 1:
                LOG.debug("Consult request sended");
                result = builder.buildSendConsultRequest(true, ref, pI, dateref, blob, null);
                break;
            case 0:
                LOG.debug("Notify request sended");
                result = builder.buildSendNotifyRequest(true, ref, pI, dateref, blob, null);
                break;
        }

        // Check all values
        LOG.debug("Check on CommonInput ...");
        Assert.assertEquals("inputreference incorrect", ref, result.getCommonInput().getInputReference());
        Assert.assertNotNull(result.getCommonInput().getOrigin());

        RequestType rT = new RequestType();
        rT.setIsTest(true);
        Assert.assertEquals("istest incorrect", rT.isIsTest(), result.getCommonInput().getRequest().isIsTest());

        LOG.debug("Check on Routing ...");
        Assert.assertEquals("Dateref incorrect", dateref.toDateMidnight(), result.getRouting().getReferenceDate().toDateMidnight());
        Assert.assertEquals("Mut incorrect", mutuality, result.getRouting().getCareReceiver().getMutuality());
        Assert.assertEquals("RegNrWithMut incorrect", regnrwithmut, result.getRouting().getCareReceiver().getRegNrWithMut());
        Assert.assertEquals("Ssin incorrect", pI.getInss(), result.getRouting().getCareReceiver().getSsin());
        Assert.assertNull(result.getRouting().getPeriod());

        LOG.debug("Check on Detail ...");
        Assert.assertEquals("Blob id type incorrect", blobid, result.getDetail().getId());
        Assert.assertEquals("Blob content type incorrect", blobcontenttype, result.getDetail().getContentType());
        Assert.assertEquals("Blob content encodingincorrect", "none", result.getDetail().getContentEncoding());

        LOG.debug("Check on Detail content  ...");
        Blob resultBlob = new Blob();
        resultBlob.setContent(result.getDetail().getValue());
        resultBlob.setContentEncoding(result.getDetail().getContentEncoding());
        resultBlob.setHashTagRequired(action.getValue() != 1); // no hashtag needed for consult
        resultBlob.setHashValue(result.getDetail().getHashValue());
        Assert.assertEquals("Blob content incorrect", ConnectorIOUtils.toString(blobcontent, Charset.UTF_8), ConnectorIOUtils.toString(bbuilder.checkAndRetrieveContent(resultBlob), Charset.UTF_8));

        LOG.debug("Check on XadesT ...");
        Assert.assertNull(result.getXadesT());

        return result;
    }
}
