/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.test.genericasync.integration;

import be.cin.mycarenet.esb.common.v2.CommonOutputType;
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.TAck;
import be.cin.nip.async.generic.TAckResponse;
import be.ehealth.business.mycarenetdomaincommons.builders.BlobBuilder;
import be.ehealth.business.mycarenetdomaincommons.builders.BlobBuilderFactory;
import be.ehealth.business.mycarenetdomaincommons.builders.CommonBuilder;
import be.ehealth.business.mycarenetdomaincommons.builders.RequestBuilderFactory;
import be.ehealth.business.mycarenetdomaincommons.domain.Blob;
import be.ehealth.business.mycarenetdomaincommons.domain.McnPackageInfo;
import be.ehealth.business.mycarenetdomaincommons.util.McnConfigUtil;
import be.ehealth.businessconnector.genericasync.domain.GenericAsyncConstants;
import be.ehealth.businessconnector.test.genericasync.integration.GenAsyncIntegrationTestUtil.PostParameter;
import be.ehealth.businessconnector.genericasync.mappers.CommonInputMapper;
import be.ehealth.businessconnector.test.genericasync.test.util.TestUtil;
import be.ehealth.technicalconnector.enumeration.Charset;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.SessionRule;
import org.junit.Rule;
import org.junit.Test;
import org.mapstruct.factory.Mappers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.ws.soap.SOAPFaultException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import static org.junit.Assert.fail;

/**
 * Consult Integration Test.
 * 
 * WARNING : Patient and doctor need to have a therapeutic link to be able to create a DMG
 * 
 * @author EHP
 * 
 */
public class GenAsyncIntegrationTest {

    private static final String SERVICE_NAME = "dmg";

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

    @Rule
    public SessionRule rule = SessionRule.withActiveSession().baseOn("/be.ehealth.businessconnector.genericasync.test.properties").build();

    @Test
    public void testConsultationList() throws Exception {
        // Params
        InputStream xmlFile = ConnectorIOUtils.getResourceAsStream("/examples/PostConsultationListeXml.xml");
        // requestIdentifier must be identical to second part of kmehr id in the test xml file!!!!
        // REPLACE STRING generated.id with actual value
        String identifierToUse = IdGeneratorFactory.getIdGenerator().generateId();
        String requestIdentifier = "$$generated.id$$";
        byte[] content = ConnectorIOUtils.getBytes(xmlFile);
        String fileContent = ConnectorIOUtils.toString(content, Charset.UTF_8);
        // replace the identifier seperately
        fileContent = TestUtil.replaceString(fileContent, requestIdentifier, identifierToUse);
        fileContent = TestUtil.fillOutPlaceHolders(fileContent);
        fileContent = fileContent.replaceAll(requestIdentifier, identifierToUse);
        content = ConnectorIOUtils.toBytes(fileContent, Charset.UTF_8);
        // now using same identifier in file and as input

        LOG.error("testing with xml file " + fileContent);
        BlobBuilder bbuilder = BlobBuilderFactory.getBlobBuilder("genericasync");
        Blob blob = bbuilder.build(content, "deflate", "_" + UUID.randomUUID().toString(), "text/xml");
        String messageName = "GMD-CONSULT-HCP";
        blob.setMessageName(messageName);
        GenAsyncIntegrationTestUtil.basePostTest(new PostParameter(blob, false, SERVICE_NAME, false, null, "urn:be:cin:nip:async:generic:post:msg", identifierToUse));
    }

    @Test
    public void testConfirmSuccessTackMessages() throws Exception {
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo(SERVICE_NAME);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(SERVICE_NAME);
        OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));
        // by not providing the type of message, we receive all messages.
        GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, SERVICE_NAME);
        // normally you would also process the contents in messages received in getResponse.
        // this is skipped here
        List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
        List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
        // only confirm successes
        tackResponseToConfirm.addAll(GenAsyncIntegrationTestUtil.selectTacksWithStatus(getResponse.getReturn().getTAckResponses(), GenericAsyncConstants.TACK_SUCCES));
        if (tackResponseToConfirm.isEmpty() && msgResponsesToConfirm.isEmpty()) {
            LOG.error("no messages to confirm , WILL NOT EXECUTE CONFIRM");
        } else {
            LOG.error("confirming " + tackResponseToConfirm.size() + " tackResponses and " + msgResponsesToConfirm.size() + " messageResponses");
            GenAsyncIntegrationTestUtil.confirm(origin, SERVICE_NAME, 300, tackResponseToConfirm, msgResponsesToConfirm);

        }
    }

    @Test(expected = SOAPFaultException.class)
    public void confirmWithEmptyItems() throws Exception {
        // test workaround for problem when no tackResponses or no MsgRsponses
        // will now throw exception javax.xml.ws.soap.SOAPFaultException: No values found in msgbox
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo(SERVICE_NAME);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(SERVICE_NAME);
        OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));
        List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
        List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
        GenAsyncIntegrationTestUtil.confirm(origin, SERVICE_NAME, null, tackResponseToConfirm, msgResponsesToConfirm);
    }


    @Test(expected = SOAPFaultException.class)
    public void confirmWithOnlyDummyMessageResponse() throws Exception {
        // test workaround for problem when no tackResponses or no MsgRsponses
        // will now throw exception javax.xml.ws.soap.SOAPFaultException: No values found in msgbox
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo(SERVICE_NAME);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(SERVICE_NAME);
        OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));
        List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
        MsgResponse dummyMsgResponse = new MsgResponse();
        be.cin.types.v1.Blob blob = new be.cin.types.v1.Blob();
        blob.setHashValue("hashValueToSend".getBytes());
        dummyMsgResponse.setDetail(blob);
        CommonOutputType dummyCommonOutput = new CommonOutputType();
        dummyCommonOutput.setInputReference("dummyInputReference");
        dummyMsgResponse.setCommonOutput(dummyCommonOutput);
        msgResponsesToConfirm.add(dummyMsgResponse);
        List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
        GenAsyncIntegrationTestUtil.confirm(origin, SERVICE_NAME, null, tackResponseToConfirm, msgResponsesToConfirm);
    }

    @Test(expected = SOAPFaultException.class)
    public void confirmWithOnlyDummyTackValue() throws Exception {
        // test workaround for problem when no tackResponses or no MsgRsponses
        // will now throw exception javax.xml.ws.soap.SOAPFaultException: No values found in msgbox
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo(SERVICE_NAME);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(SERVICE_NAME);
        OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));
        List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
        List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
        TAckResponse dummyTackResponse = new TAckResponse();
        TAck dummyTack = new TAck();
        dummyTack.setValue("dummyTackValue".getBytes());
        dummyTackResponse.setTAck(dummyTack);
        tackResponseToConfirm.add(dummyTackResponse);
        GenAsyncIntegrationTestUtil.confirm(origin, SERVICE_NAME, null, tackResponseToConfirm, msgResponsesToConfirm);
    }

    @Test
    public void testConfirmErrorTackMessages() throws Exception {
        try {
            McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo(SERVICE_NAME);
            CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(SERVICE_NAME);
            OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));
            // by not providing the type of message, we receive all messages.
            GetResponse getResponse = GenAsyncIntegrationTestUtil.get(origin, SERVICE_NAME);
            // normally you would also process the contents in messages received in getResponse.
            // this is skipped here
            List<MsgResponse> msgResponsesToConfirm = new ArrayList<MsgResponse>();
            List<TAckResponse> tackResponseToConfirm = new ArrayList<TAckResponse>();
            // only confirm errors
            tackResponseToConfirm.addAll(GenAsyncIntegrationTestUtil.selectTacksWithStatus(getResponse.getReturn().getTAckResponses(), GenericAsyncConstants.TACK_FAILURE));
            if (msgResponsesToConfirm.isEmpty()) {
                if (!tackResponseToConfirm.isEmpty()) {
                    LOG.error("tackResponses to confirm , but no messages to confirm , WILL NOT EXECUTE CONFIRM( only works when there are messages to confirm )");
                } else {
                    LOG.error("no messages to confirm , WILL NOT EXECUTE CONFIRM");
                }
            } else {
                LOG.error("confirming " + tackResponseToConfirm.size() + " tackResponses and " + msgResponsesToConfirm.size() + " messageResponses");
                GenAsyncIntegrationTestUtil.confirm(origin, SERVICE_NAME, 300, tackResponseToConfirm, msgResponsesToConfirm);

            }
        } catch (SOAPFaultException e) {
            if (e.getFault().getFaultString().startsWith("Not enough time between two calls")) {
                fail(e.getFault().getFaultString());
            } else {
                throw e;
            }
        }
    }

}
