/*
 * Copyright (c) eHealth
 */
package be.ehealth.technicalconnector.session;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

import be.ehealth.technicalconnector.beid.BeIDInfo;
import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.ConfigValidator;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.service.sts.security.Credential;
import be.ehealth.technicalconnector.service.sts.security.SAMLToken;
import be.ehealth.technicalconnector.service.sts.security.impl.BeIDCredential;
import be.ehealth.technicalconnector.service.sts.security.impl.SAMLHolderOfKeyToken;
import be.ehealth.technicalconnector.service.sts.utils.SAMLConverter;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.SessionRule;


/**
 * Class to verify is the {@link SessionManager} is working correctly.
 *
 * @author EHP
 */
public class SessionManagerUserIntegrationTest extends AbstractSessionManagerIntegrationTest {

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

    @Rule
    public ExpectedException exceptEx = ExpectedException.none();

    @ClassRule
    public static SessionRule rule = SessionRule.withInactiveSession().build();

    private static ConfigValidator config = ConfigFactory.getConfigValidator();

    private static String configuredInss;

    @BeforeClass
    public static void setup() throws Exception {
        configuredInss = config.getProperty("user.inss");
        config.setProperty("user.inss", BeIDInfo.getInstance().getIdentity().getNationalNumber());
    }

    @Test
    public void testCreateSessionWithoutEnc() throws Exception {

        SessionManager sessionmgmgt = Session.getInstance();
        sessionmgmgt.unloadSession();
        SessionItem session = sessionmgmgt.createSession(props.getProperty("test.session.holderofkey.password"));
        String token = SAMLConverter.toXMLString(session.getSAMLToken().getAssertion());

        LOG.debug(token);

        Assert.assertNotNull(token);
        Assert.assertEquals(true, sessionmgmgt.hasValidSession());
        Assert.assertNotNull(session.getEncryptionCredential());


    }

    @Test
    public void testCreateSessionWithEnc() throws Exception {


        SessionManager sessionmgmgt = Session.getInstance();
        sessionmgmgt.unloadSession();
        SessionItem session = sessionmgmgt.createSession(props.getProperty("test.session.holderofkey.password"), props.getProperty("test.session.encryption.password"));
        String token = SAMLConverter.toXMLString(session.getSAMLToken().getAssertion());

        LOG.debug(token);
        List<String> expectedProps = new ArrayList<String>();
        ConfigValidator config = ConfigFactory.getConfigValidator(expectedProps);

        Assert.assertNotNull(config.getProperty("user.inss"));
        Assert.assertNotNull(token);
        Assert.assertEquals(true, sessionmgmgt.hasValidSession());
        Assert.assertNotNull(session.getEncryptionCredential());

    }

    /**
     * Test create session. Create a session based on the eID
     */
    @Test
    public void testCreateSessionEidOnlyUserInssPropertyEmpty() throws Exception {
        ConfigFactory.getConfigValidator().setProperty("user.inss", "");
        SessionManager sessionmgmgt = Session.getInstance();
        sessionmgmgt.unloadSession();
        SessionItem session = sessionmgmgt.createSessionEidOnly();
        String userInss = ConfigFactory.getConfigValidator().getProperty("user.inss");
        Assert.assertNotNull(userInss);
        Assert.assertTrue("property userInss should be filled out with the inss from the eid : checked if was a valid inss (check : length = 11 ) inss: " + userInss, userInss.length() == 11);
        String token = SAMLConverter.toXMLString(session.getSAMLToken().getAssertion());

        LOG.debug(token);

        Assert.assertNotNull(token);
        Assert.assertEquals(true, sessionmgmgt.hasValidSession());
        Assert.assertNotNull(session.getEncryptionCredential());

    }

    /**
     * Test create session. Create a session based on the eID
     */
    @Test
    public void testCreateSessionEidOnly() throws Exception {
        ConfigFactory.getConfigValidator().setProperty("user.inss", "");
        SessionManager sessionmgmgt = Session.getInstance();
        sessionmgmgt.unloadSession();
        SessionItem session = sessionmgmgt.createSessionEidOnly();
        String token = SAMLConverter.toXMLString(session.getSAMLToken().getAssertion());

        LOG.debug(token);

        Assert.assertNotNull(token);
        Assert.assertEquals(true, sessionmgmgt.hasValidSession());
        Assert.assertNotNull(session.getEncryptionCredential());

    }

    @Test
    public void testRenewToken() throws Exception {
        if (!configuredInss.equalsIgnoreCase(config.getProperty("user.inss"))) {
            exceptEx.expect(TechnicalConnectorException.class);
            exceptEx.expectMessage("The certificate from the ETK don't match with the one in the encryption keystore");
        }

        ConfigFactory.getConfigValidator().setProperty("sessionmanager.activate.autorenew", "true");
        SessionManager sessionmgmgt = Session.getInstance();
        String sas = ConnectorIOUtils.convertStreamToString(ConnectorIOUtils.getResourceAsStream("/examples/sas/renew.eid.sas"));
        sas = StringUtils.replace(sas, "${user.inss}", ConfigFactory.getConfigValidator().getProperty("user.inss"));
        Element tokenEl = SAMLConverter.toElement(sas);

        Credential authCredential = BeIDCredential.getInstance("session", BeIDCredential.EID_AUTH_ALIAS);
        sessionmgmgt.getSession().setHeaderCredential(authCredential);
        SAMLToken token = new SAMLHolderOfKeyToken(tokenEl, authCredential);
        sessionmgmgt.loadSession(token, props.getProperty("test.session.holderofkey.password"), props.getProperty("test.session.encryption.password"));
        Assert.assertEquals(true, sessionmgmgt.hasValidSession());
        Assert.assertNotNull(sessionmgmgt.getSession().getEncryptionCredential());

        ConfigFactory.getConfigValidator().setProperty("sessionmanager.activate.autorenew", "false");
    }

}
