/*
 * Copyright (c) eHealth
 */
using be.cin.mycarenet.esb.common.v2;
using be.cin.nip.async.generic;
using be.ehealth.business.mycarenetdomaincommons.builders;
using be.ehealth.business.mycarenetdomaincommons.domain;
using be.ehealth.business.mycarenetdomaincommons.mapper;
using be.ehealth.business.mycarenetdomaincommons.util;
using be.ehealth.businessconnector.genericasync.builders;
using be.ehealth.businessconnector.genericasync.exception;
using be.ehealth.businessconnector.genericasync.mappers;
using be.ehealth.businessconnector.genericasync.session;
using be.ehealth.businessconnector.genericasync.domain;
using be.ehealth.businessconnector.test.testcommons.utils;
using be.ehealth.technicalconnector.exception;
using be.ehealth.technicalconnector.handler.domain;
using be.ehealth.technicalconnector.utils;
using be.ehealth.technicalconnector.service.keydepot;
using org.apache.commons.lang;
using org.slf4j;
using org.mapstruct.factory;
using System;
using ikvm.extensions;
using java.lang;
using java.io;
using java.net;
using java.util;
using NUnit.Framework;

namespace be.ehealth.businessconnector.genericasync.test.helper
{


public class GetAndConfirmTestHelper {

	private static Logger LOG = LoggerFactory.getLogger(typeof(GetAndConfirmTestHelper));

    private string projectName;
    private string outputFileExtension;
    private string outputDir;
    private int maxMessages;
    private java.util.List messageNames;
    private BusinessResponseValidator businessResponseValidator;
    private GenAsyncService service;
    private OrigineType origin;
    private bool replyToEtk;
   

    private GetAndConfirmTestHelper(Builder builder) {
        projectName = builder.projectName;
        outputFileExtension = builder.outputFileExtension;
        outputDir = builder.outputDir;
        maxMessages = builder.maxMessages;
        messageNames = builder.messageNames;
        businessResponseValidator = builder.businessResponseValidator;
        service = GenAsyncSessionServiceFactory.getGenAsyncService(projectName);
        origin = givenOrigin();
        replyToEtk = builder.replyToEtk;
    }

    public static Builder builder() {
        return new Builder();
    }


    public void checkIfTAckResponsesWithSameReferencesAreStillReturned(java.util.List tAckResponseReferences) {
        Validate.notEmpty(tAckResponseReferences, "Add tAckResponse references you wish to check to the tAckResponseReferences list");
                    
        OrigineType origin = givenOrigin();
       
        GetResponse messages = getMessages(origin, service);
        Responses messageReturn = messages.getReturn();
        if (messageReturn.getTAckCount() != 0) {
            java.util.List tackValues = messageReturn.getTAckResponses();
            for (int i = 0; i < tackValues.size(); i++){
                TAckResponse tackResp = (TAckResponse) tackValues.get(i);
                string reference = tackResp.getTAck().getReference();
                if (tAckResponseReferences.contains(reference)) {
                    Assert.Fail("\tTackResponse found after it was already confirmed : reference: >" + reference + "< , appliesTo >" + tackResp.getTAck().getAppliesTo() + "< " + tackResp.getTAck().getResultMessage());
                }
            }
        }
    }

    public void checkIfMessagesWithSameReferencesAreStillReturned(java.util.List msgResponseReferences) {
        Validate.notEmpty(msgResponseReferences, "Add msgResponse references you wish to check to the msgResponseReferences list");
                    
        OrigineType origin = givenOrigin();


        GetResponse messages = getMessages(origin, service);
        Responses messageReturn = messages.getReturn();
        if (messageReturn.getMsgCount() != 0) {
           java.util.List msgValues = messageReturn.getMsgResponses();
            for (int i = 0; i < msgValues.size(); i++) {
                MsgResponse msgResponse = (MsgResponse) msgValues.get(i);
                string reference = msgResponse.getDetail().getReference();
                if (msgResponseReferences.contains(reference)) {
                    Assert.Fail("\tmessageResponse found even after its reception was already confirmed : reference: >" + msgResponse.getDetail().getReference() + "< , inputRef : " + msgResponse.getCommonOutput().getInputReference() + " outputRef: " + msgResponse.getCommonOutput().getOutputReference());
                }
            }
        }
    }
    
    private OrigineType givenOrigin() {
        McnPackageInfo packageInfo = McnConfigUtil.retrievePackageInfo("genericasync." + projectName);
        CommonBuilder commonBuilder = RequestBuilderFactory.getCommonBuilder(projectName);
        CommonInputMapper mapper = (CommonInputMapper) Mappers.getMapper(typeof(CommonInputMapper));
        return mapper.map(commonBuilder.createOrigin(packageInfo));
    }


    public GetResponse performGetAndConfirm(bool confirmMessages) {
        OrigineType origin = givenOrigin();
            
        GetResponse getResponse = getMessages(origin, service);
        
        if (getResponse.getReturn().getMsgCount() == 0 && getResponse.getReturn().getTAckCount() == 0) {
            LOG.warn("NO MESSAGES TO CONFIRM ");
        } else if (confirmMessages) {
            ConfirmResponse confirmResponse = confirmTheseMessages(origin, service, getResponse);
            LOG.debug(ConnectorXmlUtils.toString(confirmResponse));
            Assert.NotNull(confirmResponse);
        }
        return getResponse;
    }

    private GetResponse getMessages(OrigineType origin, GenAsyncService service) {
        MsgQuery msgQuery = new MsgQuery();
        msgQuery.setInclude(new java.lang.Boolean(true));
        msgQuery.setMax(new java.lang.Integer(maxMessages));
        msgQuery.getMessageNames().addAll(messageNames);
        
        Query tackQuery = new Query();
        tackQuery.setInclude(new java.lang.Boolean(true));
        tackQuery.setMax(new java.lang.Integer(maxMessages));
        
        WsAddressingHeader getResponseHeader = WsAddressingUtil.createHeader(null, GenericAsyncConstants.GET_SOAP_ACTION);
        GetResponse getResponse = service.getRequest(BuilderFactory.getRequestObjectBuilder(projectName)
                                         .buildGetRequest(origin, msgQuery, tackQuery,
                                          replyToEtk ? KeyDepotManagerFactory.getKeyDepotManager().getETK(KeyDepotManager.EncryptionTokenType.HOLDER_OF_KEY).getEncoded() : null),
                                           getResponseHeader);
        
        // validate the get responses ( including check on xades if present)
        BuilderFactory.getResponseObjectBuilder().handleGetResponse(getResponse);
        
        processGetResponse(getResponse);
        
        return getResponse;
    }
    

    private ConfirmResponse confirmTheseMessages(OrigineType origin, GenAsyncService service, GetResponse getResponse) {
        WsAddressingHeader responseConfirmHeader = WsAddressingUtil.createHeader(null, GenericAsyncConstants.CONFIRM_SOAP_ACTION);
        Confirm request = BuilderFactory.getRequestObjectBuilder(projectName).buildConfirmWithReferences(origin, getResponse);
        ConfirmResponse confirmResponse = service.confirmRequest(request, responseConfirmHeader);
        return confirmResponse;
    }

    private void processGetResponse(GetResponse getResponse) {
        processMsgResponses(getResponse);
        processTAckResponses(getResponse);
        FileTestUtils.writeToFile(System.Text.Encoding.UTF8.GetString(ConnectorXmlUtils.toByteArray(getResponse)), "getResponse", outputFileExtension, outputDir);
        ConnectorXmlUtils.dump(getResponse);
    }

    private void processTAckResponses(GetResponse getResponse) {
        java.util.List tackValues = getResponse.getReturn().getTAckResponses();
        for (int i = 0; i < tackValues.size(); i++) {
            TAckResponse tAckResponse = (TAckResponse) tackValues.get(i);
            string tack = ConnectorXmlUtils.toString(tAckResponse.getTAck());
             
	        // handle with your own logic
	        FileTestUtils.writeToFile(tack, "tackResponseValue", outputFileExtension, outputDir);
	        LOG.debug("received Tack response : " + tack);
        }
    }

    private void processMsgResponses(GetResponse getResponse) {
        java.util.List msgResponses = getResponse.getReturn().getMsgResponses();
        for (int i = 0; i < msgResponses.size(); i++) {
            MsgResponse msgResponse = (MsgResponse) msgResponses.get(i);
            Blob mappedBlob = DomainBlobMapper.mapToBlob(msgResponse.getDetail());
            
            // No hash in message response
            mappedBlob.setHashTagRequired(false);
            
            byte[] unwrappedMessageByteArray = BlobBuilderFactory.getBlobBuilder(projectName).checkAndRetrieveContent(mappedBlob);
             
            if (unwrappedMessageByteArray != null & unwrappedMessageByteArray.Length > 0) {
                if(msgResponse.getDetail().getContentEncryption() != null) {
            		ProcessedMsgResponse processedMsgResponse = BuilderFactory.getResponseObjectBuilder().processEncryptedResponse(msgResponse, projectName, typeof(byte[]));
                    validateBusinessResponse((byte[]) processedMsgResponse.getBusinessResponse());
                } else {
                    validateBusinessResponse(unwrappedMessageByteArray);
                }
            
                // handle the business message with your own logic
                FileTestUtils.writeToFile(System.Text.Encoding.UTF8.GetString(unwrappedMessageByteArray), "getResponseBusinessMessage", outputFileExtension, outputDir);
                LOG.debug("received Business Message : " + System.Text.Encoding.UTF8.GetString(unwrappedMessageByteArray));
            }
        }
    }

    private void validateBusinessResponse(byte[] unwrappedMessageByteArray) {
        if (businessResponseValidator != null) {
            businessResponseValidator.validate(System.Text.Encoding.UTF8.GetString(unwrappedMessageByteArray));
        }
    }


    public class Builder {
        public string projectName;
        public string outputFileExtension;
        public string outputDir;
        public int maxMessages;
        public java.util.List messageNames = new ArrayList();
        public BusinessResponseValidator businessResponseValidator;
        public bool replyToEtk;

        public Builder() {
        }

        public Builder withProjectName(string projectName) {
            this.projectName = projectName;
            return this;
        }

        public Builder withOutputFileExtension(string outputFileExtension) {
            this.outputFileExtension = outputFileExtension;
            return this;
        }
        
        public Builder withOutputDir(string outputDir) {
            this.outputDir = outputDir;
            return this;
        }

        public Builder withMaxMessages(int maxMessages) {
            this.maxMessages = maxMessages;
            return this;
        }

        public Builder withMessageNames(java.util.List messageNames) {
            if (messageNames != null) {
                this.messageNames.addAll(messageNames);
            }    
            return this;
        }

        public Builder BusinessResponseValidator(BusinessResponseValidator businessResponseValidator) {
            this.businessResponseValidator = businessResponseValidator;
            return this;
        }
        
        public Builder isReplyToEtk(bool replyToEtk) {
            this.replyToEtk = replyToEtk;
            return this;
        }	

        public GetAndConfirmTestHelper build() {
            return new GetAndConfirmTestHelper(this);
        }
    }

    public interface BusinessResponseValidator {
        void validate(string blobValue);
    }
    
}
}
