package be.fgov.ehealth.technicalconnector.services.daas;

import be.fgov.ehealth.technicalconnector.services.ServiceFactory;
import be.fgov.ehealth.technicalconnector.test.tests.junit.rule.SessionRule;
import be.fgov.ehealth.technicalconnector.test.tests.utils.LoggingUtils;
import org.apache.commons.codec.binary.StringUtils;
import org.hamcrest.CustomMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static be.fgov.ehealth.technicalconnector.services.daas.AttributeValue.ValueType.ACTOR;
import static be.fgov.ehealth.technicalconnector.services.daas.AttributeValue.ValueType.ROUTING_INFORMATION;
import static be.fgov.ehealth.technicalconnector.services.daas.AttributeValue.ValueType.STRING;
import static be.fgov.ehealth.technicalconnector.services.daas.DaasAssertionUtils.assertAttributeValue;
import static org.junit.Assert.assertEquals;

/**
 * @author EHP
 */
public class DataAttributeServiceIntegrationTest {

    @ClassRule
    public static SessionRule rule = SessionRule.withActiveSession()
            .baseOn("/be.ehealth.technicalconnector.daas.test.properties")
            .build();
    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @BeforeClass
    public static void before() {
        LoggingUtils.bootstrap();
    }

    @Test
    public void listOfPreventionServices() throws Exception {

        Map<String, List<String>> attr = new HashMap<String, List<String>>();
        String ssin = rule.getTestProperty("test.daas.success.ssin");
        attr.put("urn:be:fgov:person:ssin", Arrays.asList(ssin));
        attr.put("urn:be:fgov:person:ssin:ehealth:1.0:listofpreventionservices", null);
        attr.put("urn:be:fgov:ehealth:1.0:service-name", Arrays.asList(rule.getTestProperty("test.daas.success.service-name")));

        Map<String, List<AttributeValue>> result = ServiceFactory.getDataAttributeService().invoke(attr);

        assertEquals(attr.size(), result.size());
        assertAttributeValue(result, "urn:be:fgov:person:ssin", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:ehealth:1.0:service-name", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:person:ssin:ehealth:1.0:listofpreventionservices", 1, ACTOR);

    }

    @Test
    public void multemediattRouting_cookbook_scenario_03() throws Exception {

        Map<String, List<String>> attr = new HashMap<String, List<String>>();
        attr.put("urn:be:fgov:person:ssin", Arrays.asList("75411615563"));
        attr.put("urn:be:fgov:person:ssin:incapacity:cause", Arrays.asList("illness"));
        attr.put("urn:be:fgov:person:ssin:birthdate", Arrays.asList("16/01/1975"));
        attr.put("urn:be:fgov:person:ssin:incapacity:prolongation", Arrays.asList("false"));
        attr.put("urn:be:fgov:person:ssin:incapacity:totalincapacity", Arrays.asList("true"));
        attr.put("urn:be:fgov:person:ssin:multemediatt:routing", null);
        attr.put("urn:be:fgov:ehealth:1.0:service-name", Arrays.asList("urn:be:fgov:ehealth:admin:simplification:multemediatt"));

        Map<String, List<AttributeValue>> result = ServiceFactory.getDataAttributeService().invoke(attr, Instant.now(), Instant.now().plus(21, ChronoUnit.DAYS));

        assertEquals(attr.size(), result.size());
        assertAttributeValue(result, "urn:be:fgov:person:ssin", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:ehealth:1.0:service-name", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:person:ssin:multemediatt:routing", 1, ROUTING_INFORMATION);

    }

    @Test
    public void multemediattRouting_cookbook_scenario_04() throws Exception {

        Map<String, List<String>> attr = new HashMap<String, List<String>>();
        attr.put("urn:be:fgov:person:ssin", Arrays.asList("92410907531"));
        attr.put("urn:be:fgov:person:ssin:incapacity:cause", Arrays.asList("workaccident"));
        attr.put("urn:be:fgov:person:ssin:birthdate", Arrays.asList("09/01/1992"));
        attr.put("urn:be:fgov:person:ssin:incapacity:prolongation", Arrays.asList("false"));
        attr.put("urn:be:fgov:person:ssin:incapacity:totalincapacity", Arrays.asList("true"));
        attr.put("urn:be:fgov:person:ssin:multemediatt:routing", null);
        attr.put("urn:be:fgov:ehealth:1.0:service-name", Arrays.asList("urn:be:fgov:ehealth:admin:simplification:multemediatt"));

        Map<String, List<AttributeValue>> result = ServiceFactory.getDataAttributeService().invoke(attr, Instant.now(), Instant.now().plus(1, ChronoUnit.DAYS));

        assertEquals(attr.size(), result.size());
        assertAttributeValue(result, "urn:be:fgov:person:ssin", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:ehealth:1.0:service-name", 1, STRING);
        assertAttributeValue(result, "urn:be:fgov:person:ssin:multemediatt:routing", 1, ROUTING_INFORMATION);

    }

    @Test
    public void multemediattRouting_scenario_03() throws Exception {

        expectedException.expect(DaasServiceException.class);
        expectedException.expectMessage("Error DAAS: Digital Incapacity Notifications are currently not supported for a patient of age lower than 16 years");
        expectedException.expect(hasStatusLevelAmount(2));
        expectedException.expect(hasStatusLevel(1, "urn:oasis:names:tc:SAML:2.0:status:Requester"));
        expectedException.expect(hasStatusLevel(2, "urn:be:fgov:ehealth:2.0:status:RequestUnsupported"));

        Map<String, List<String>> attr = new HashMap<String, List<String>>();
        attr.put("urn:be:fgov:person:ssin", Arrays.asList("16412708740"));
        attr.put("urn:be:fgov:person:ssin:incapacity:cause", Arrays.asList("illness"));
        attr.put("urn:be:fgov:person:ssin:birthdate", Arrays.asList("27/01/2017"));
        attr.put("urn:be:fgov:person:ssin:incapacity:prolongation", Arrays.asList("true"));
        attr.put("urn:be:fgov:person:ssin:incapacity:totalincapacity", Arrays.asList("true"));
        attr.put("urn:be:fgov:person:ssin:multemediatt:routing", null);
        attr.put("urn:be:fgov:ehealth:1.0:service-name", Arrays.asList("urn:be:fgov:ehealth:admin:simplification:multemediatt"));

        ServiceFactory.getDataAttributeService().invoke(attr, Instant.now(), Instant.now().plus(6, ChronoUnit.DAYS));

    }

    @Test
    public void invalidSSIN() throws Exception {

        expectedException.expect(DaasServiceException.class);
        expectedException.expectMessage("Error DAAS: Attribute urn:be:fgov:person:ssin could not be resolved: Invalid input");

        Map<String, List<String>> attr = new HashMap<String, List<String>>();
        attr.put("urn:be:fgov:person:ssin", Arrays.asList("1234567"));
        attr.put("urn:be:fgov:person:ssin:ehealth:1.0:listofpreventionservices", null);
        attr.put("urn:be:fgov:ehealth:1.0:service-name", Arrays.asList("urn:be:fgov:ehealth:admin:simplification:backtowork"));

        ServiceFactory.getDataAttributeService().invoke(attr);

    }

    private static Matcher<DaasServiceException> hasStatusLevelAmount(final int i) {
        return new CustomMatcher<DaasServiceException>("Verify amount of statusLevels equals " + i) {
            @Override
            public boolean matches(Object o) {
                DaasServiceException e = (DaasServiceException) o;
                return e.getStatusLevels().size() == i;
            }
        };
    }

    private static Matcher<DaasServiceException> hasStatusLevel(final int i, final String status) {
        return new CustomMatcher<DaasServiceException>("Verify is statusLevel on position " + i + " equals " + status) {

            @Override
            public boolean matches(Object o) {
                DaasServiceException e = (DaasServiceException) o;
                return StringUtils.equals(e.getStatusLevel(i), status);
            }

            @Override
            public void describeMismatch(Object o, Description description) {
                DaasServiceException e = (DaasServiceException) o;
                super.describeMismatch(e.getStatusLevel(i), description);
            }
        };
    }


}