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

import be.cin.mycarenet.esb.common.v2.CommonInput;
import be.cin.mycarenet.esb.common.v2.OrigineType;
import be.cin.nip.async.generic.Confirm;
import be.cin.nip.async.generic.ConfirmResponse;
import be.cin.nip.async.generic.GetResponse;
import be.cin.nip.async.generic.MsgQuery;
import be.cin.nip.async.generic.MsgResponse;
import be.cin.nip.async.generic.Post;
import be.cin.nip.async.generic.PostResponse;
import be.cin.nip.async.generic.Query;
import be.cin.nip.async.generic.TAckResponse;
import be.ehealth.business.mycarenetcommons.builders.util.BlobUtil;
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.mapper.DomainBlobMapper;
import be.ehealth.business.mycarenetdomaincommons.util.McnConfigUtil;
import be.ehealth.business.mycarenetdomaincommons.util.WsAddressingUtil;
import be.ehealth.businessconnector.genericasync.builders.BuilderFactory;
import be.ehealth.businessconnector.genericasync.builders.ResponseObjectBuilder;
import be.ehealth.businessconnector.genericasync.exception.GenAsyncBusinessConnectorException;
import be.ehealth.businessconnector.genericasync.mappers.CommonInputMapper;
import be.ehealth.businessconnector.genericasync.session.GenAsyncService;
import be.ehealth.businessconnector.genericasync.session.GenAsyncSessionServiceFactory;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.handler.domain.WsAddressingHeader;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import org.junit.Assert;
import org.mapstruct.factory.Mappers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

/**
 * Usage example of the genAsync code.
 * 
 * @author eh076
 *
 */
public class GenAsyncUsageTemplate {


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

    private static final String PROJECT_NAME = "the name of your project as configured in the property file";

    private static final String MESSAGE_NAME = "the name of the messageType , ex : HCPFAC for invoicing request";

    private static final String MESSAGE_NAME_2 = "the name of the messageType , ex : HCPFAC for invoicing request";

    private static final String mutuality = "the mutuality to send the message to ex : 100";

    public void usePostRequest() throws Exception {

        byte[] contentBytes = "the flat file or xml file content of your business request".getBytes();

        BlobBuilder bbuilder = BlobBuilderFactory.getBlobBuilder(PROJECT_NAME);

        Blob blob = bbuilder.build(contentBytes);
        blob.setMessageName(MESSAGE_NAME);

        String inputReference = IdGeneratorFactory.getIdGenerator().generateId();
        CommonInput ci = Mappers.getMapper(CommonInputMapper.class).map(RequestBuilderFactory.getCommonBuilder(PROJECT_NAME).createCommonInput(McnConfigUtil.retrievePackageInfo("genericasync." + PROJECT_NAME), true, inputReference));

        byte[] xades = BlobUtil.generateXadesForBlob(blob, PROJECT_NAME).getValue();

        Post post = BuilderFactory.getRequestObjectBuilder(PROJECT_NAME).buildPostRequest(ci, DomainBlobMapper.mapBlobToCinBlob(blob), xades);

        LOG.debug("Send of the post request");
        GenAsyncService service = GenAsyncSessionServiceFactory.getGenAsyncService(PROJECT_NAME);

        WsAddressingHeader header = WsAddressingUtil.createHeader(mutuality, "urn:be:cin:nip:async:generic:post:msg");

        PostResponse responsePost = service.postRequest(post, header);
        // we have utility methods to dump the contents to log
        // ConnectorXmlUtils.dump(responsePost);

        LOG.debug("Call of handler for the post operation");
        ResponseObjectBuilder responseBuilder = BuilderFactory.getResponseObjectBuilder();
        // we validate and check for warnings in the response
        boolean hasWarnings = responseBuilder.handlePostResponse(responsePost);
        if (hasWarnings) {
            LOG.info("The post has warnings");
        } else {
            LOG.info("The post has no warnings");
        }
    }

    public void retrieveResponses() throws Exception {
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo("genericasync." + PROJECT_NAME);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(PROJECT_NAME);
        OrigineType origin = Mappers.getMapper(CommonInputMapper.class).map(commonBuilder.createOrigin(packageInfo));

        GenAsyncService service = GenAsyncSessionServiceFactory.getGenAsyncService(PROJECT_NAME);
        LOG.debug("Creation of the get");
        MsgQuery msgQuery = new MsgQuery();
        msgQuery.setInclude(true);
        msgQuery.setMax(100);
        msgQuery.getMessageNames().add(MESSAGE_NAME);
        msgQuery.getMessageNames().add(MESSAGE_NAME_2);

        Query tackQuery = new Query();
        tackQuery.setInclude(true);
        tackQuery.setMax(100);

        LOG.debug("Send of the get request");
        WsAddressingHeader responseGetHeader = WsAddressingUtil.createHeader(null, "urn:be:cin:nip:async:generic:get:query");
        GetResponse responseGet1 = service.getRequest(BuilderFactory.getRequestObjectBuilder(PROJECT_NAME).buildGetRequest(origin, msgQuery, tackQuery), responseGetHeader);
        // validate the get responses ( including check on xades if present)
        // no need to verify that the xades is present ( if its not , mycarenet would have rejected the message ), the handleGetResponse
        // will check if the xades signature is valid if there is a xades signature
        BuilderFactory.getResponseObjectBuilder().handleGetResponse(responseGet1);
        List<byte[]> treatedMsgHashValues = new ArrayList<byte[]>();
        List<byte[]> treatedTackHashValues = new ArrayList<byte[]>();
        for (MsgResponse msgResponse : responseGet1.getReturn().getMsgResponses()) {
            Blob mappedBlob = DomainBlobMapper.mapToBlob(msgResponse.getDetail());
            // the check and retrieve content will check if the hash value is correct , and perform the automatic decryption and deflation
            // if needed
            byte[] unwrappedMessageByteArray = BlobBuilderFactory.getBlobBuilder(PROJECT_NAME).checkAndRetrieveContent(mappedBlob);
            if (unwrappedMessageByteArray != null & unwrappedMessageByteArray.length > 0) {
                // handle the business message with your own logic
                // writeToFile(unwrappedMessageByteArray, "getResponseBusinessMessage");
                LOG.debug("received Business Message : " + new String(unwrappedMessageByteArray));
            }
            // you should confirm to mycarenet that you have treated the message
            treatedMsgHashValues.add(msgResponse.getDetail().getHashValue());

        }
        for (TAckResponse tackResponse : responseGet1.getReturn().getTAckResponses()) {
            byte[] tackResponseBytes = tackResponse.getTAck().getValue();
            if (tackResponseBytes != null & tackResponseBytes.length > 0) {
                // handle with your own logic
                // writeToFile(tackResponseBytes, "tackResponseValue");
                LOG.debug("received Tack response : " + new String(tackResponseBytes, "UTF-8"));
            }
            treatedTackHashValues.add(tackResponse.getTAck().getValue());
        }
        // send confirmation message for all treated messages, if you don't do this , the next call to get method will return these messages
        // again.
        confirmTreatmentOfMessages(origin, service, treatedMsgHashValues, treatedTackHashValues);

    }

    /**
     * 
     * @param origin
     * @param service
     * @param treatedMsgHashValues
     * @param treatedTackHashValues
     * @throws URISyntaxException
     * @throws TechnicalConnectorException
     * @throws GenAsyncBusinessConnectorException
     */
    private void confirmTreatmentOfMessages(OrigineType origin, GenAsyncService service, List<byte[]> treatedMsgHashValues, List<byte[]> treatedTackHashValues) throws URISyntaxException, TechnicalConnectorException, GenAsyncBusinessConnectorException {
        WsAddressingHeader responseConfirmHeader = new WsAddressingHeader(new URI("urn:be:cin:nip:async:generic:confirm:hash"));
        responseConfirmHeader.setTo(new URI(""));
        responseConfirmHeader.setFaultTo("http://www.w3.org/2005/08/addressing/anonymous");
        responseConfirmHeader.setReplyTo("http://www.w3.org/2005/08/addressing/anonymous");
        responseConfirmHeader.setMessageID(new URI(IdGeneratorFactory.getIdGenerator("uuid").generateId()));

        Confirm request = new Confirm();
        request.setOrigin(origin);
        request.getMsgHashValues().addAll(treatedMsgHashValues);
        request.getTAckContents().addAll(treatedTackHashValues);
        ConfirmResponse confirmResponse = service.confirmRequest(request, responseConfirmHeader);
        // the confirmResponse does not contain any special info.
        Assert.assertNotNull(confirmResponse);
    }

}
