package be.ehealth.businessconnector.test.mycarenet.memberdatav2.session;

import be.ehealth.businessconnector.mycarenet.memberdatav2.builders.ResponseObjectBuilder;
import be.ehealth.businessconnector.mycarenet.memberdatav2.builders.ResponseObjectBuilderFactory;
import be.ehealth.businessconnector.mycarenet.memberdatav2.domain.MemberDataBuilderResponse;
import be.ehealth.businessconnector.mycarenet.memberdatav2.session.MemberDataService;
import be.ehealth.businessconnector.mycarenet.memberdatav2.session.MemberDataSessionServiceFactory;
import be.ehealth.businessconnector.test.mycarenet.memberdatav2.session.builders.BuilderStrategy;
import be.ehealth.businessconnector.test.testcommons.utils.FileTestUtils;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.MarshallerHelper;
import be.fgov.ehealth.errors.core.v1.LocalisedStringType;
import be.fgov.ehealth.errors.soa.v1.BusinessError;
import be.fgov.ehealth.mycarenet.memberdata.protocol.v1.MemberDataConsultationRequest;
import be.fgov.ehealth.mycarenet.memberdata.protocol.v1.MemberDataConsultationResponse;
import be.fgov.ehealth.technicalconnector.signature.domain.SignatureVerificationResult;
import be.fgov.ehealth.technicalconnector.tests.utils.XmlAsserter;
import oasis.names.tc.saml._2_0.protocol.AttributeQuery;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.junit.Test;

import javax.xml.soap.DetailEntry;
import javax.xml.ws.soap.SOAPFaultException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public abstract class AbstractCareProviderIntegrationTest extends AbstractIntegrationTest {

    private static final String REQUEST_LOCATION_HAPPY = "/scenarios/careprovider-request-happy.xml";

    private static final String REQUEST_LOCATION_UNHAPPY = "/scenarios/careprovider-request-unhappy.xml";

    private static final String RESPONSE_LOCATION_HAPPY = "/scenarios/careprovider-response-happy.xml";

    private static final String DEFAULT_VALUE = "BLABLA";

    private String enehID;

    private String enxsID;

    private String cnchID;

    private String cnxsID;

    public AbstractCareProviderIntegrationTest(String enehID, String enxsID, String cnchID, String cnxsID) {
        this.enehID = enehID;
        this.enxsID = enxsID;
        this.cnchID = cnchID;
        this.cnxsID = cnxsID;
    }

    @Test
    public void happyConsultationWithoutEncryption() throws Exception {
        happyConsultationTest(UNENCRYPTED_STRATEGY, cnchID);
    }

    @Test
    public void happyConsultationWithEncryption() throws Exception {
        happyConsultationTest(ENCRYPTED_STRATEGY, enehID);
    }

    @Test
    public void unhappyConsultationWithoutEncryption() throws Exception {
        unhappyConsultationTest(UNENCRYPTED_STRATEGY, cnxsID);
    }

    @Test
    public void unhappyConsultationWithEncryption() throws Exception {
        unhappyConsultationTest(ENCRYPTED_STRATEGY, enxsID);
    }

    private void happyConsultationTest(BuilderStrategy strategy, String inputReference) throws Exception {
        Map<String, Object> testFileParams = new HashMap<String, Object>();

        testFileParams.put("id", inputReference);
        testFileParams.put("nihii", DEFAULT_VALUE);
        testFileParams.put("niss", DEFAULT_VALUE);

        AttributeQuery attributeQuery = FileTestUtils.toObject(testFileParams, REQUEST_LOCATION_HAPPY, AttributeQuery.class);

        MemberDataConsultationRequest memberDataRequest = buildRequest(inputReference, strategy, attributeQuery);

        MemberDataService service = MemberDataSessionServiceFactory.getMemberDataSyncService();
        MemberDataConsultationResponse wsResponse = service.consultMemberData(memberDataRequest);

        ResponseObjectBuilder responseBuilder = ResponseObjectBuilderFactory.getResponseObjectBuilder();
        MemberDataBuilderResponse response = responseBuilder.handleConsultationResponse(wsResponse);

        Map<String, SignatureVerificationResult> signVerifResult = response.getSignatureVerificationResult();
        for (Map.Entry<String, SignatureVerificationResult> entry : signVerifResult.entrySet()) {
            Assert.assertTrue("Errors found in the signature verification",
                    entry.getValue().isValid());
        }

        InputStream is = ConnectorIOUtils.getResourceAsStream(RESPONSE_LOCATION_HAPPY);
        String expectedresponse = ConnectorIOUtils.convertStreamToString(is);
        IOUtils.closeQuietly(is);

        byte[] details = response.getResponse();

        XmlAsserter.assertSimilar(expectedresponse, new String(details, "UTF-8"));
    }

    private void unhappyConsultationTest(BuilderStrategy strategy, String inputReference) throws Exception {
        Map<String, Object> testFileParams = new HashMap<String, Object>();

        testFileParams.put("content", DEFAULT_VALUE.toLowerCase());

        String requestContent = FileTestUtils.toString(testFileParams, REQUEST_LOCATION_UNHAPPY);

        MemberDataConsultationRequest memberDataRequest = buildRequest(inputReference, strategy, requestContent);

        MemberDataService service = MemberDataSessionServiceFactory.getMemberDataSyncService();

        try {
            service.consultMemberData(memberDataRequest);
            Assert.fail("soap fault expected");
        } catch (SOAPFaultException sfe) {
            checkSOAPFault(sfe);
        }
    }

    private void checkSOAPFault(SOAPFaultException sfe) {
        List<DetailEntry> entries = new ArrayList<DetailEntry>();
        Iterator it = sfe.getFault().getDetail().getDetailEntries();
        while (it.hasNext()) entries.add((DetailEntry) it.next());

        Assert.assertEquals(1, entries.size());

        MarshallerHelper<BusinessError, BusinessError> helper = new MarshallerHelper<BusinessError, BusinessError>(BusinessError.class, BusinessError.class);
        BusinessError error = helper.toObject(entries.get(0));

        Assert.assertEquals("INVALID_DETAIL_REQUEST", error.getCode());
        Assert.assertEquals("MYCARENET", error.getOrigin());

        List<LocalisedStringType> messages = error.getMessages();
        Assert.assertEquals(1, messages.size());

        LocalisedStringType message = messages.get(0);
        Assert.assertEquals("Detail XML structure is not valid against schema.", message.getValue());
    }

}
