package be.fgov.ehealth.technicalconnector.bootstrap.tsl;

import be.ehealth.technicalconnector.config.ConfigFactory;
import be.ehealth.technicalconnector.config.impl.ConfigurationFake;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.fgov.ehealth.technicalconnector.tests.utils.LoggingUtils;
import org.junit.Assert;
import org.junit.Test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;

public class TrustStoreUpdaterIntegrationTest {


    private static File createStore(String name, String initialLoad, String initialLoadPwd) throws Exception {
        final File caCertificateStore = File.createTempFile(name + ".", ".jks");
        final KeyStore store = KeyStore.getInstance("JKS");
        if (initialLoad != null) {
            store.load(ConnectorIOUtils.getResourceAsStream(initialLoad), initialLoadPwd.toCharArray());
        } else {
            store.load(null, null);
        }
        store.store(new FileOutputStream(caCertificateStore), "unknown".toCharArray());
        return caCertificateStore;
    }

    private static KeyStore getKeystore(File file, String pwd) throws Exception {
        final KeyStore store = KeyStore.getInstance("JKS");
        store.load(new FileInputStream(file), pwd.toCharArray());
        return store;
    }

    private static ConfigurationFake getConfigurationFake(File caCertificateStore, File trustStore, File tsloStore, File tsaStore, String environment) throws TechnicalConnectorException, IOException {
        final ConfigurationFake configuration = new ConfigurationFake();
        configuration.setProperty("environment", environment);
        configuration.setProperty("KEYSTORE_DIR", "");
        configuration.setProperty("be.fgov.ehealth.technicalconnector.bootstrap.tsl.keystore.location", tsloStore.getAbsolutePath());
        configuration.setProperty("be.fgov.ehealth.technicalconnector.bootstrap.tsl.keystore.pwd", "unknown");
        configuration.setProperty("truststoreupdater.local.cache", File.createTempFile("local-cache", ".jks").getAbsolutePath());
        configuration.setProperty("CAKEYSTORE_LOCATION", caCertificateStore.getAbsolutePath());
        configuration.setProperty("CAKEYSTORE_PASSWORD", "unknown");
        configuration.setProperty("truststore_location", trustStore.getAbsolutePath());
        configuration.setProperty("truststore_password", "unknown");
        configuration.setProperty("timestamp.signature.keystore.path", tsaStore.getAbsolutePath());
        configuration.setProperty("timestamp.signature.keystore.pwd", "unknown");
        return configuration;
    }

    @Test
    public void acceptance() throws Exception {
        final File caCertificateStore = createStore("caCertificateStore", "/P12/acc/tslostore.jks", "tslo");
        final File trustStore = createStore("trustStore", null, null);
        final File tsloStore = createStore("tslo", "/P12/acc/tslostore.jks", "tslo");
        final File tsaStore = createStore("tsacertificate", null, null);

        ConfigFactory.setConfiguration(getConfigurationFake(caCertificateStore, trustStore, tsloStore, tsaStore, "acc"));

        Assert.assertEquals(1, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(0, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(1, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(0, getKeystore(tsaStore, "unknown").size());

        LoggingUtils.bootstrap();
        TrustStoreUpdater.launch();

        Assert.assertEquals(10, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(153, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(2, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(10, getKeystore(tsaStore, "unknown").size());

        ConfigFactory.setConfiguration(getConfigurationFake(caCertificateStore, trustStore, tsloStore, tsaStore, "acc"));
        TrustStoreUpdater.launch();

        Assert.assertEquals(10, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(153, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(2, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(10, getKeystore(tsaStore, "unknown").size());

        ConfigFactory.setConfiguration(null);
    }

    @Test
    public void prod() throws Exception {
        final File caCertificateStore = createStore("caCertificateStore", "/P12/prod/tslostore.jks", "tslo");
        final File trustStore = createStore("trustStore", null, null);
        final File tsloStore = createStore("tslo", "/P12/prod/tslostore.jks", "tslo");
        final File tsaStore = createStore("tsacertificate", null, null);


        ConfigFactory.setConfiguration(getConfigurationFake(caCertificateStore, trustStore, tsloStore, tsaStore, "prd"));

        Assert.assertEquals(1, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(0, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(1, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(0, getKeystore(tsaStore, "unknown").size());

        LoggingUtils.bootstrap();
        TrustStoreUpdater.launch();

        Assert.assertEquals(20, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(154, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(3, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(27, getKeystore(tsaStore, "unknown").size());

        ConfigFactory.setConfiguration(getConfigurationFake(caCertificateStore, trustStore, tsloStore, tsaStore, "prd"));
        TrustStoreUpdater.launch();

        Assert.assertEquals(20, getKeystore(caCertificateStore, "unknown").size());
        Assert.assertEquals(154, getKeystore(trustStore, "unknown").size());
        Assert.assertEquals(3, getKeystore(tsloStore, "unknown").size());
        Assert.assertEquals(27, getKeystore(tsaStore, "unknown").size());

        ConfigFactory.setConfiguration(null);
    }

}