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

import be.ehealth.technicalconnector.beid.BeIDFactory;
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.session.renew.RenewStrategyFactory;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.technicalconnector.tests.junit.rule.SessionRule;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.util.encoders.Base64;
import org.junit.*;
import org.junit.rules.ExpectedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;


/**
 * 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();



    @BeforeClass
    public static void setup() throws Exception {
        ConfigFactory.getConfigValidator().setProperty("user.inss",  BeIDFactory.getBeIDInfo("test",false)
                .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 {
        SessionManager sessionmgmgt = Session.getInstance();
        ConfigFactory.getConfigValidator().setProperty("user.inss", "");
        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 {
        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"));
        sas = StringUtils.replace(sas, "${hok}", new String(Base64.encode(BeIDCredential.getInstance("session", BeIDCredential.EID_AUTH_ALIAS).getCertificate().getEncoded())));
        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"));

        RenewStrategyFactory.get().flushCache();

        Assert.assertEquals(true, sessionmgmgt.hasValidSession());

        Assert.assertNotNull(sessionmgmgt.getSession().getEncryptionCredential());

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

    @Test
    public void testUnloadLoad() throws Exception {
        ConfigFactory.getConfigValidator().setProperty("user.inss", "");
        SessionManager sessionmgmgt = Session.getInstance();
        sessionmgmgt.createSessionEidOnly();
        sessionmgmgt.unloadSession();
        JOptionPane.showMessageDialog(null, "Please insert the new eID?", "Waiting...", JOptionPane.QUESTION_MESSAGE);
        sessionmgmgt.createSessionEidOnly();
    }

}
