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

import be.ehealth.business.mycarenetdomaincommons.domain.InputReference;
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.test.mycarenet.memberdatav2.session.builders.BuilderStrategy;
import be.ehealth.businessconnector.test.testcommons.utils.FileTestUtils;
import be.ehealth.technicalconnector.utils.ConnectorXmlUtils;
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.junit.rule.SessionRule;
import oasis.names.tc.saml._2_0.protocol.AttributeQuery;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Test;

import javax.xml.ws.soap.SOAPFaultException;
import java.util.HashMap;
import java.util.Map;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThrows;

public abstract class AbstractMobilityImprovementIntegrationTest {

    @ClassRule
    public static SessionRule rule = SessionRule.withActiveSession().forEnvironment("acc").forProfession("persotmobilityimprovement").forUser("nicolas").build();

    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 INPUT_REFERENCE = "AAA1130000";

    private final MemberDataService memberDataService;

    private final BuilderStrategy encryptedStrategy;

    private final BuilderStrategy unencryptedStrategy;


    public AbstractMobilityImprovementIntegrationTest(MemberDataService memberDataService, BuilderStrategy encryptedStrategy, BuilderStrategy unencryptedStrategy) {
        this.memberDataService = memberDataService;
        this.encryptedStrategy = encryptedStrategy;
        this.unencryptedStrategy = unencryptedStrategy;
    }

    @Test
    public void happyConsultationWithoutEncryption() throws Exception {
        happyConsultationTest(unencryptedStrategy);
    }

    @Test
    public void happyConsultationWithEncryption() throws Exception {
        happyConsultationTest(encryptedStrategy);
    }

    @Test
    public void unhappyConsultationWithoutEncryption() throws Exception {
        unhappyConsultationTest(unencryptedStrategy);
    }

    @Test
    public void unhappyConsultationWithEncryption() throws Exception {
        unhappyConsultationTest(encryptedStrategy);
    }

    private void happyConsultationTest(BuilderStrategy strategy) throws Exception {
        Map<String, Object> testFileParams = new HashMap<String, Object>();
        testFileParams.put("id", INPUT_REFERENCE);
        testFileParams.put("nihii", "99627512009");
        testFileParams.put("niss", "49112002395");
        AttributeQuery attributeQuery = FileTestUtils.toObject(testFileParams, REQUEST_LOCATION_HAPPY, AttributeQuery.class);
        MemberDataConsultationRequest memberDataRequest = buildRequest(strategy, attributeQuery);
        MemberDataConsultationResponse wsResponse = memberDataService.consultMemberData(memberDataRequest);
        ResponseObjectBuilder responseBuilder = ResponseObjectBuilderFactory.getResponseObjectBuilder();
        MemberDataBuilderResponse response = responseBuilder.handleConsultationResponse(wsResponse);

        verifySignature(response);
        assertNotNull(response.getResponse());
    }

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

    private void unhappyConsultationTest(BuilderStrategy strategy) throws Exception {
        Map<String, Object> testFileParams = new HashMap<String, Object>();
        testFileParams.put("content", "blabla");
        String requestContent = FileTestUtils.toString(testFileParams, REQUEST_LOCATION_UNHAPPY);
        MemberDataConsultationRequest memberDataRequest = buildRequest(strategy, requestContent);
        assertThrows(SOAPFaultException.class, () -> memberDataService.consultMemberData(memberDataRequest));
    }

    private MemberDataConsultationRequest buildRequest(BuilderStrategy strategy, Object content) throws Exception {
        ConnectorXmlUtils.dump(content);

        // input reference and AttributeQuery ID must match
        InputReference inputReference = new InputReference(INPUT_REFERENCE);

        return strategy.build(true, inputReference, content);
    }
}
