package com.sonymusic.delphi.log4j;

import net.logstash.log4j.JSONEventLayoutV1;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.*;

public class DatadogSocketAppenderTest {

    private Logger logger;
    private ServerSocket serverSocket;
    private String apiKey;

    @Before
    public void setUp() throws IOException {
        apiKey = UUID.randomUUID().toString();
        serverSocket = new ServerSocket(0);

        JSONEventLayoutV1 layout = new JSONEventLayoutV1();
        layout.setLocationInfo(false);

        Logger.getRootLogger().getLoggerRepository().resetConfiguration();
        DatadogTcpSocketAppender datadogSocketAppender = new DatadogTcpSocketAppender();
        datadogSocketAppender.setName("test");
        datadogSocketAppender.setApiKey(apiKey);
        datadogSocketAppender.setHost("localhost");
        datadogSocketAppender.setPort(serverSocket.getLocalPort());
        datadogSocketAppender.setLayout(layout);
        datadogSocketAppender.activateOptions();

        logger = Logger.getRootLogger();
        logger.setLevel(Level.ALL);
        logger.addAppender(datadogSocketAppender);
    }

    @After
    public void tearDown() throws IOException {
        Logger.getRootLogger().getLoggerRepository().resetConfiguration();
        serverSocket.close();
    }

    @Test
    public void testAllLogsShouldBeDeliveredToServer() throws InterruptedException {
        int logMessagesCount = 10;
        final CountDownLatch countDownLatch = new CountDownLatch(logMessagesCount);
        final List<String> messages = new ArrayList<>();

        new Thread(() -> {
            try (Socket socket = serverSocket.accept();
                 BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {

                while (true) {
                    String message = reader.readLine();
                    messages.add(message);
                    countDownLatch.countDown();
                }
            } catch (IOException e) {
                fail(e.getMessage());
            }
        }).start();

        for (int i = 0; i < logMessagesCount; i++) {
            logger.info(String.format("Log message #%s", i));
        }
        countDownLatch.await(1, TimeUnit.MINUTES);

        List<String> notEmptyMessages = messages.stream()
                .map(String::trim)
                .filter(x -> !x.isEmpty())
                .collect(Collectors.toList());

        assertEquals(logMessagesCount, notEmptyMessages.size());

        List<String> apiKeys = notEmptyMessages.stream().map(x -> x.split(" ")[0]).collect(Collectors.toList());
        assertThat(apiKeys, everyItem(is(apiKey)));
    }
}
