/*
 * 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.oscore.logging.core.itest;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.Security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import com.scytl.products.oscore.logging.api.domain.Level;
import com.scytl.products.oscore.logging.api.domain.LogContent;
import com.scytl.products.oscore.logging.api.domain.LogContent.LogContentBuilder;
import com.scytl.products.oscore.logging.api.factory.LoggingFactory;
import com.scytl.products.oscore.logging.api.formatter.MessageFormatter;
import com.scytl.products.oscore.logging.api.writer.LoggingWriter;
import com.scytl.products.oscore.logging.core.factory.LoggingFactoryLog4j;
import com.scytl.products.oscore.logging.core.formatter.SplunkFormatter;
import com.scytl.products.oscore.logging.core.provider.TransactionInfoProvider;

/**
 * Integration test to verify the logging system case of use
 */
public class LoggingIntegrationTest {
    private Path folder;

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

    @BeforeClass
    public static void beforeClass() {
        if (Security
            .getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    @Before
    public void setUp() {
        folder = Paths.get("target/logs").toAbsolutePath();
    }

    @Test
    public void itShouldLogWithLog4jWithDifferentLoggers()
            throws Exception {

        // 0. configuration is loaded from test classpath: log4j2.xml
        // create transaction info provider and transaction info.
        TransactionInfoProvider provider = new TransactionInfoProvider();

        provider.generate("FAKE_TENANT", "192.168.1.1", "127.0.0.1");

        // 1. create an log by using LogContent class
        LogContentBuilder builder = new LogContentBuilder();
        builder.logEvent(LogEventTest.TEST_EVENT);
        builder.objectType("objectType");
        builder.objectId("objectId");
        builder.user("userID");
        builder.electionEvent("123456789");
        builder.additionalInfo("message", "test compatibility log4j");
        builder.additionalInfo("errorcode", "0");
        builder.additionalInfo("exception", "no error");

        LogContent content = builder.createLogInfo();

        // 2. create instance of MessageFormatter
        MessageFormatter formatter =
            new SplunkFormatter("APPLICATION", "MODULE", provider);

        // 3. create single instance of factory, ideally is use ejb
        LoggingFactory loggerFactory = new LoggingFactoryLog4j(formatter);

        // 4. obtain LoggingWriter instance
        final LoggingWriter writer =
            loggerFactory.getLogger(LoggingIntegrationTest.class);

        Path infoFile = folder.resolve("info-log4j.log").toAbsolutePath();
        Path errorFile = folder.resolve("error-log4j.log");
        Path warnFile = folder.resolve("warn-log4j.log");
        Path debugFile = folder.resolve("debug-log4j.log");

        long infoSize = Files.exists(infoFile) ? Files.size(infoFile) : 0;
        long errorSize =
            Files.exists(errorFile) ? Files.size(errorFile) : 0;
        long warnSize = Files.exists(warnFile) ? Files.size(warnFile) : 0;
        long debugrSize =
            Files.exists(debugFile) ? Files.size(debugFile) : 0;

        writer.log(Level.DEBUG, content);
        writer.log(Level.INFO, content);
        writer.log(Level.WARN, content);
        writer.log(Level.ERROR, content);

        Assert.assertTrue(Files.size(infoFile) > infoSize);
        Assert.assertTrue(Files.size(errorFile) > errorSize);
        Assert.assertTrue(Files.size(warnFile) > warnSize);
        Assert.assertTrue(Files.size(debugFile) > debugrSize);
    }

    @Test
    public void itShouldLogWithLog4jWithDifferentLoggersOnlyWithMandatoryFields()
            throws Exception {

        // 0. configuration is loaded from test classpath: log4j2.xml
        // create transaction info provider and transaction info.
        TransactionInfoProvider provider = new TransactionInfoProvider();

        provider.generate("FAKE_TENANT", "192.168.1.1", "127.0.0.1");

        // 1. create an log by using LogContent class
        final LogContentBuilder builder = new LogContentBuilder();
        builder.logEvent(LogEventTest.TEST_EVENT);
        builder.user("userID");
        builder.additionalInfo("message", "test compatibility log4j");
        builder.additionalInfo("errorcode", "0");
        builder.additionalInfo("exception", "no error");

        final LogContent content = builder.createLogInfo();

        // 2. create instance of MessageFormatter
        final MessageFormatter formatter =
            new SplunkFormatter("APPLICATION", "MODULE", provider);

        // 3. create single instance of factory, ideally is use ejb
        final LoggingFactory loggerFactory =
            new LoggingFactoryLog4j(formatter);

        Path infoFile = folder.resolve("info-log4j.log").toAbsolutePath();
        Path errorFile = folder.resolve("error-log4j.log");
        Path warnFile = folder.resolve("warn-log4j.log");
        Path debugFile = folder.resolve("debug-log4j.log");

        long infoSize = Files.exists(infoFile) ? Files.size(infoFile) : 0;
        long errorSize =
            Files.exists(errorFile) ? Files.size(errorFile) : 0;
        long warnSize = Files.exists(warnFile) ? Files.size(warnFile) : 0;
        long debugrSize =
            Files.exists(debugFile) ? Files.size(debugFile) : 0;

        // 4. obtain LoggingWriter instance
        final LoggingWriter writer =
            loggerFactory.getLogger(LoggingIntegrationTest.class);
        writer.log(Level.DEBUG, content);
        writer.log(Level.INFO, content);
        writer.log(Level.WARN, content);
        writer.log(Level.ERROR, content);

        Assert.assertTrue(Files.size(infoFile) > infoSize);
        Assert.assertTrue(Files.size(errorFile) > errorSize);
        Assert.assertTrue(Files.size(warnFile) > warnSize);
        Assert.assertTrue(Files.size(debugFile) > debugrSize);
    }
}
