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

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

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

import be.cin.mycarenet.esb.common.v2.OrigineType;
import be.cin.nip.async.generic.GetResponse;
import be.cin.nip.async.generic.MsgResponse;
import be.cin.nip.async.generic.PostResponse;
import be.cin.nip.async.generic.Responses;
import be.cin.nip.async.generic.TAck;
import be.cin.nip.async.generic.TAckResponse;
import be.ehealth.business.kmehrcommons.HcPartyUtil;
import be.ehealth.business.mycarenetcommons.builders.BlobBuilder;
import be.ehealth.business.mycarenetcommons.builders.BlobBuilderFactory;
import be.ehealth.business.mycarenetcommons.builders.CommonBuilder;
import be.ehealth.business.mycarenetcommons.builders.RequestBuilderFactory;
import be.ehealth.business.mycarenetcommons.domain.Blob;
import be.ehealth.businessconnector.dmg.builders.ResponseObjectBuilderFactory;
import be.ehealth.businessconnector.dmg.domain.DmgBuilderResponse;
import be.ehealth.businessconnector.dmg.util.DmgConstants;
import be.ehealth.businessconnector.dmg.util.DmgTestUtils;
import be.ehealth.businessconnector.genericasync.domain.GenericAsyncConstants;
import be.ehealth.businessconnector.genericasync.integration.GenAsyncIntegrationTestUtil;
import be.ehealth.businessconnector.genericasync.integration.GenAsyncIntegrationTestUtil.PostParameter;
import be.ehealth.businessconnector.genericasync.mappers.CommonInputMapper;
import be.ehealth.businessconnector.genericasync.test.util.TestUtil;
import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.util.ConfigUtil;
import be.ehealth.technicalconnector.config.util.domain.PackageInfo;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.ConnectorXmlUtils;
import be.fgov.ehealth.messageservices.core.v1.RequestType;
import be.fgov.ehealth.messageservices.core.v1.RetrieveTransactionRequest;
import be.fgov.ehealth.messageservices.core.v1.RetrieveTransactionResponse;
import be.fgov.ehealth.messageservices.core.v1.SelectRetrieveTransactionType;
import be.fgov.ehealth.messageservices.core.v1.TransactionType;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDERRORMYCARENET;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTRANSACTION;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTRANSACTIONschemes;
import be.fgov.ehealth.standards.kmehr.schema.v1.AuthorType;
import be.fgov.ehealth.standards.kmehr.schema.v1.ErrorMyCarenetType;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;


/**
 * test the asynchronous operations for dmg. this code calls the external async project with the parameters for dmg.
 * 
 * @author EHP
 * 
 */
public class DmgAsyncIntegrationTest {

    /**
     * 
     */
    private static final String GMD_TRANSACTION_CODE = "gmd";

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


    @BeforeClass
    public static final void setupsession() throws Exception {
        LOG.debug("DmgAsyncIntegrationTest.loadSession:");
        SessionInitializer.init("/be.ehealth.businessconnector.dmg.test.properties");
    }

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

    @Test
    public void consultAllDMGsTest() throws Exception {
        // Params : isTest moet false zijn, no support for test requests on pilot
        Boolean istest = false;

        // create the request
        AuthorType author = HcPartyUtil.createAuthor(DmgConstants.PROJECT_IDENTIFIER);
        DateTime now = new DateTime(DateTimeZone.forID("GMT"));
        now = now.withMillisOfSecond(0);

        RetrieveTransactionRequest retrieveTransactionRequest = new RetrieveTransactionRequest();
        RequestType request = new RequestType();
        String inputReference = IdGeneratorFactory.getIdGenerator().generateId();
        if (istest) {
            inputReference = "T" + inputReference.substring(1);
        }
        request.setId(HcPartyUtil.createKmehrId(DmgConstants.PROJECT_IDENTIFIER, inputReference));
        request.setAuthor(author);
        request.setDate(now);
        request.setTime(now);
        retrieveTransactionRequest.setRequest(request);
        TransactionType transactions = new TransactionType();
        transactions.setAuthor(author);
        DateTime beginDate = new DateTime(2013, 1, 1, 0, 0, 0, 0);
        transactions.setBegindate(beginDate);

        CDTRANSACTION myCarenetTransaction = new CDTRANSACTION();
        myCarenetTransaction.setS(CDTRANSACTIONschemes.CD_TRANSACTION_MYCARENET);
        myCarenetTransaction.setSV("1.0");
        myCarenetTransaction.setValue(GMD_TRANSACTION_CODE);
        transactions.getCds().add(myCarenetTransaction);
        SelectRetrieveTransactionType select = new SelectRetrieveTransactionType();
        retrieveTransactionRequest.setSelect(select);
        select.setTransaction(transactions);


        byte[] content = ConnectorXmlUtils.toByteArray(retrieveTransactionRequest);


        String contentString = new String(content);
        // TODO : terug uitschakelen : tijdelijke fix voor probleem bij OA 300
        // contentString = contentString.replaceAll("\\+\\d\\d:\\d\\d</ns2:time>", "</ns2:time>");
        // content = contentString.getBytes();
        //

        LOG.debug("created RetrieveTransactionRequest: " + contentString);
        BlobBuilder bbuilder = BlobBuilderFactory.getBlobBuilder("genericasync");
        Blob blob = bbuilder.build(content, "deflate", "_" + UUID.randomUUID().toString(), "text/xml");
        String messageName = DmgConstants.GMD_CONSULT_HCP;
        blob.setMessageName(messageName);
        PostParameter postParameter = new PostParameter(blob, istest, "dmg", false, 300, "urn:be:cin:nip:async:generic:post:msg", inputReference);
        PostResponse post = GenAsyncIntegrationTestUtil.post(postParameter);
        Assert.assertNotNull(post);
        Assert.assertNotNull(post.getReturn());
        Assert.assertEquals("urn:nip:tack:result:major:success", post.getReturn().getResultMajor());

    }

    @Test
    public void testReplace() throws Exception {
        String before = "<ns2:time>12:04:01+01:00</ns2:time>";
        String expected = "<ns2:time>12:04:01</ns2:time>";
        before = before.replaceAll("\\+\\d\\d:\\d\\d</ns2:time>", "</ns2:time>");
        Assert.assertEquals(before, expected, before);
    }

    @Test
    // @Ignore("example code : not really suited for unit test : you don't really know when you will recieve these messages")
    public void checkForGmdClosuresTest() throws Exception {
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(commonBuilder.createOrigin(packageInfo));
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg", DmgConstants.GMD_CLOSURE);
        Responses responseReturn = getResponse.getReturn();
        for (MsgResponse msgResponse : responseReturn.getMsgResponses()) {
            Assert.assertNotNull(msgResponse.getDetail());
            DmgBuilderResponse response = ResponseObjectBuilderFactory.getResponseObjectBuilder().handleAsyncResponse(msgResponse);
            Assert.assertNotNull(response.getResponse());
            Assert.assertNotNull(response.getKmehrmessage());
        }
    }

    @Test
    @Ignore("example code : not really suited for unit test : you don't really know when you will recieve these messages")
    public void checkForGmdConsultResponsesTest() throws Exception {
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        ConfigFactory.getConfigValidator().setProperty("be.ehealth.businessconnector.dmg.builders.impl.dumpMessages", "true");
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(commonBuilder.createOrigin(packageInfo));
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg", DmgConstants.GMD_CONSULT_HCP);
        Responses responseReturn = getResponse.getReturn();
        DmgTestUtils.logGetResponse(responseReturn);
        boolean errorsFound = false;

        for (MsgResponse msgResponse : responseReturn.getMsgResponses()) {
            Assert.assertNotNull(msgResponse.getDetail());
            DmgBuilderResponse response = ResponseObjectBuilderFactory.getResponseObjectBuilder().handleAsyncResponse(msgResponse);
            Assert.assertNotNull(response.getResponse());
            RetrieveTransactionResponse retrieveTransactionResponse = response.getRetrieveTransactionResponse();
            Assert.assertNotNull(retrieveTransactionResponse);
            logRetrieveTransactionResponse(retrieveTransactionResponse);
            List<ErrorMyCarenetType> errors = retrieveTransactionResponse.getAcknowledge().getErrors();
            if (errors != null && !errors.isEmpty()) {
                errorsFound = true;
                LOG.error("\nmessage with error :---------------------------------------------------------\n" + new String(response.getResponse()) + "\n\n\n");
            }
        }
        if (errorsFound) {
            Assert.fail("errors found , see previous lines ");
        }
    }

    @Test
    // @Ignore("example code : not really suited for unit test : you don't really know when you will recieve these messages")
    public void checkForAnyResponsesTest() throws Exception {
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER).createOrigin(packageInfo));
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg");
        Responses responseReturn = getResponse.getReturn();
        DmgTestUtils.logGetResponse(responseReturn);
    }

    /**
     * @param msgResponse
     */
    private void logRetrieveTransactionResponse(RetrieveTransactionResponse retrieveTransactionResponse) {
        StringBuilder logBuilder = new StringBuilder();
        logBuilder.append("logging retrieveTransactionResponse : [");
        if (retrieveTransactionResponse != null) {
            logBuilder.append(ConnectorXmlUtils.toString(retrieveTransactionResponse));
        } else {
            logBuilder.append("null");
        }
        logBuilder.append("]");
        LOG.error("retrieved async retrieveTransactionResponse : \n" + ConnectorXmlUtils.toString(retrieveTransactionResponse));
        List<ErrorMyCarenetType> errors = retrieveTransactionResponse.getAcknowledge().getErrors();
        if (errors != null && !errors.isEmpty()) {
            for (ErrorMyCarenetType errorType : errors) {
                logBuilder.append("\n error : " + errorType.getDescription().getValue() + " url :" + errorType.getUrl() + " cds:[");
                for (CDERRORMYCARENET code : errorType.getCds()) {
                    logBuilder.append(code.getValue()).append(" ");
                }
                logBuilder.append("]");
            }
        }

    }

    @Test
    public void checkAndLogTackResponses() throws Exception {
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(commonBuilder.createOrigin(packageInfo));
        // BuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER).buildOrigin();
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg", DmgConstants.GMD_CONSULT_HCP);
        Responses responseReturn = getResponse.getReturn();
        StringBuilder sb = new StringBuilder("tack results : -------------------------------------------------");
        for (TAckResponse tackResponse : responseReturn.getTAckResponses()) {
            TAck tAck = tackResponse.getTAck();
            TestUtil.addTackToSb(sb, tAck);
        }
        sb.append("\n-------------------------------------------------------------------------------------");
        LOG.error(sb.toString());
    }


    @Test
    // @Ignore("example code : not really suited for unit test : you don't really know when you will recieve these messages")
    public void checkForGmdExtensionsTest() throws Exception {
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(commonBuilder.createOrigin(packageInfo));
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg", DmgConstants.GMD_EXTENSION);
        Responses responseReturn = getResponse.getReturn();
        for (MsgResponse msgResponse : responseReturn.getMsgResponses()) {
            Assert.assertNotNull(msgResponse.getDetail());
            DmgBuilderResponse response = ResponseObjectBuilderFactory.getResponseObjectBuilder().handleAsyncResponse(msgResponse);
            Assert.assertNotNull(response.getResponse());
            Assert.assertNotNull(response.getKmehrmessage());
        }
    }

    @Test
    // @Ignore("example code : not really suited for unit test : you don't really know when you will recieve these messages")
    public void confirmReceivedMessages() throws Exception {
        final boolean confirmEnabled = true;
        PackageInfo packageInfo = ConfigUtil.retrievePackageInfo(DmgConstants.PROJECT_IDENTIFIER);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(DmgConstants.PROJECT_IDENTIFIER);
        OrigineType origin = CommonInputMapper.mapOrigin(commonBuilder.createOrigin(packageInfo));
        // by not providing the type of message, we receive all messages.
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, "dmg");
        // normally you would also process the contents in messages received in getResponse.
        // this is skipped here
        List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
        // add all messages except these from a certain date ( today? )
        // for (MsgResponse msgResponse : getResponse.getReturn().getMsgResponses()) {
        // String inputReference = msgResponse.getCommonOutput().getInputReference();
        // LOG.error(inputReference);
        // if (inputReference != null && !inputReference.contains("0140319") && !inputReference.contains("014032")) {
        // msgResponsesToConfirm.add(msgResponse);
        // } else {
        // LOG.error("skipping inputReference " + inputReference);
        // }
        // }
        // Add all messages
        msgResponsesToConfirm.addAll(getResponse.getReturn().getMsgResponses());
        List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
        // only confirm successes
        tackResponseToConfirm.addAll(GenAsyncIntegrationTestUtil.selectTacksWithStatus(getResponse.getReturn().getTAckResponses(), GenericAsyncConstants.TACK_SUCCES));
        // only confirm errors
        tackResponseToConfirm.addAll(GenAsyncIntegrationTestUtil.selectTacksWithStatus(getResponse.getReturn().getTAckResponses(), GenericAsyncConstants.TACK_FAILURE));
        if (tackResponseToConfirm.isEmpty() && msgResponsesToConfirm.isEmpty()) {
            LOG.error("no messages to confirm , WILL NOT EXECUTE CONFIRM : current confirm setting : confirm=" + confirmEnabled);
        } else {
            LOG.error("confirming " + tackResponseToConfirm.size() + " tackResponses and " + msgResponsesToConfirm.size() + " messageResponses");
            if (confirmEnabled) {
                GenAsyncIntegrationTestUtil.confirm(origin, DmgConstants.PROJECT_IDENTIFIER, 300, tackResponseToConfirm, msgResponsesToConfirm);
                LOG.error("confirmed " + tackResponseToConfirm.size() + " tacks and " + msgResponsesToConfirm.size() + " messages from the " + getResponse.getReturn().getMsgCount() + " msg and " + getResponse.getReturn().getTAckCount() + " tacks");
            } else {
                LOG.error("CONFIRM DISABLED AT THE MOMENT , WONT EXECUTE");
            }

        }

    }


}
