/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.commons.logging.config;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.security.PublicKey;

import org.apache.commons.io.FileUtils;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.certificates.bean.X509CertificateType;
import com.scytl.products.ov.commons.beans.domain.model.platform.LoggingInitializationState;
import com.scytl.products.ov.commons.logging.domain.model.LoggingKeystoreEntity;
import com.scytl.products.ov.commons.logging.domain.model.LoggingKeystoreRepository;
import com.scytl.products.ov.commons.logging.producers.SecureLoggerProducer;
import com.scytl.slogger.SecureLoggerException;

import mockit.Expectations;
import mockit.Mocked;

public class SecureLoggerInitializerTest {

    private final String context = "AU";

    private final String loggingPasswordsFileName = "logging_AU.properties";

    private final String encryptionPasswordsPropertiesKey = "AU_log_encryption";

    private final String signingPasswordsPropertiesKey = "AU_log_signing";

    private final String encryptionKeystoreFilename = "auLoggingEncryptionKeystore.p12";

    private final String signingKeystoreFilename = "auLoggingSigningKeystore.p12";

    private static final String DB_ENCRYPTION_KEY_TYPE = X509CertificateType.ENCRYPT.name();

    private static final String DB_SIGNING_KEY_TYPE = X509CertificateType.SIGN.name();

    private static final String ENCRYPTION_KEYSTORE_BASE64 =
        "[encoded data, 4888 characters]";

    private static final String SIGNING_KEYSTORE_BASE64 =
        "[encoded data, 4868 characters]";

    @Test
    public void whenInitializeFromDbThenOk(@Mocked final LoggingKeystoreRepository loggingKeystoreRepository,
            @Mocked final LoggingInitializationState loggingInitializationState,
            @Mocked final SecureLoggerConfig secureLoggerConfig, @Mocked final AuditLoggerConfig auditLoggerConfig)
            throws GeneralCryptoLibException, SecureLoggerException, URISyntaxException, IOException {

        prepareEnvironment();

        SecureLoggerInitializer secureLoggerInitializer = new SecureLoggerInitializer(loggingInitializationState,
            loggingKeystoreRepository, context, encryptionPasswordsPropertiesKey, signingPasswordsPropertiesKey);

        LoggingKeystoreEntity loggingKeystoreEntityEncryption = new LoggingKeystoreEntity();
        loggingKeystoreEntityEncryption.setKeystoreContent(ENCRYPTION_KEYSTORE_BASE64);

        LoggingKeystoreEntity loggingKeystoreEntitySigning = new LoggingKeystoreEntity();
        loggingKeystoreEntitySigning.setKeystoreContent(SIGNING_KEYSTORE_BASE64);

        new Expectations() {
            {

                loggingKeystoreRepository.checkIfKeystoreExists(DB_ENCRYPTION_KEY_TYPE);
                result = true;
                times = 1;

                loggingKeystoreRepository.checkIfKeystoreExists(DB_SIGNING_KEY_TYPE);
                result = true;
                times = 1;

                loggingKeystoreRepository.getLoggingKeystoreByType(DB_ENCRYPTION_KEY_TYPE);
                result = loggingKeystoreEntityEncryption;
                times = 1;

                loggingKeystoreRepository.getLoggingKeystoreByType(DB_SIGNING_KEY_TYPE);
                result = loggingKeystoreEntitySigning;
                times = 1;

                secureLoggerConfig.configure(SecureLoggerProducer.LOGGER_NAME_SECURE_LOGGER, (PrivateKey) any, (PrivateKey) any,
                    (PublicKey) any);
                times = 1;

                auditLoggerConfig.configure(SecureLoggerProducer.LOGGER_NAME_AUDIT_LOGGER, (PrivateKey) any, (PrivateKey) any,
                    (PublicKey) any);
                times = 1;
            }
        };

        secureLoggerInitializer.initializeIfDataExistsInDB();
    }

    @Test
    public void whenInitializeFromUploadedDataThenOk(@Mocked final LoggingKeystoreRepository loggingKeystoreRepository,
            @Mocked final LoggingInitializationState loggingInitializationState,
            @Mocked final SecureLoggerConfig secureLoggerConfig, @Mocked final AuditLoggerConfig auditLoggerConfig)
            throws GeneralCryptoLibException, SecureLoggerException, URISyntaxException, IOException {

        prepareEnvironment();

        SecureLoggerInitializer secureLoggerInitializer = new SecureLoggerInitializer(loggingInitializationState,
            loggingKeystoreRepository, context, encryptionPasswordsPropertiesKey, signingPasswordsPropertiesKey);

        new Expectations() {
            {
                secureLoggerConfig.configure(SecureLoggerProducer.LOGGER_NAME_SECURE_LOGGER, (PrivateKey) any, (PrivateKey) any,
                    (PublicKey) any);
                times = 1;

                auditLoggerConfig.configure(SecureLoggerProducer.LOGGER_NAME_AUDIT_LOGGER, (PrivateKey) any, (PrivateKey) any,
                    (PublicKey) any);
                times = 1;
            }
        };

        secureLoggerInitializer.initializeFromUploadData(ENCRYPTION_KEYSTORE_BASE64, SIGNING_KEYSTORE_BASE64);
    }

    private void prepareEnvironment() throws URISyntaxException, IOException {

        String externalSourceOfLoggingPasswords =
            Paths.get(getClass().getClassLoader().getResource("passwords/logging_AU.properties").toURI())
                .toAbsolutePath().toString();
        File externalSourceOfLoggingPasswordsAsFile = new File(externalSourceOfLoggingPasswords);

        String destinationDirectoryAsString = Paths
            .get(getClass().getClassLoader().getResource("productionPasswordsDir").toURI()).toAbsolutePath().toString();
        Path destinationFileAsPath = Paths.get(destinationDirectoryAsString, loggingPasswordsFileName);
        File desintationDirectoryAsFile = new File(destinationFileAsPath.toAbsolutePath().toString());

        FileUtils.copyFile(externalSourceOfLoggingPasswordsAsFile, desintationDirectoryAsFile);
        System.setProperty("loggingpasswordsdirectory", destinationDirectoryAsString);
    }
}
