package com.atlassian.bitbucket.mesh.logback;

import ch.qos.logback.classic.LoggerContext;
import com.atlassian.bitbucket.mesh.request.RequestContext;
import com.atlassian.bitbucket.mesh.request.RequestManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import java.util.Optional;

import static com.atlassian.bitbucket.mesh.logback.RequestContextConverter.OBJ_REQUEST_MANAGER;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class RequestContextConverterTest {

    private RequestContextConverter converter;
    @Mock
    private LoggerContext loggerContext;
    @Mock
    private RequestContext requestContext;
    @Mock
    private RequestManager requestManager;

    @Before
    public void setup() {
        //Logback invariants: A LoggerContext is always set and start() is always called before
        //convert(ILoggingEvent) is ever called
        converter = new RequestContextConverter();
        converter.setContext(loggerContext);
        converter.start();
    }

    @Test
    public void testConvert() {
        when(loggerContext.getObject(eq(OBJ_REQUEST_MANAGER))).thenReturn(requestManager);
        when(requestManager.getContext()).thenReturn(Optional.of(requestContext));

        when(requestContext.getAction()).thenReturn("action");
        when(requestContext.getCorrelationId()).thenReturn("correlationId");
        when(requestContext.getId()).thenReturn("id");
        when(requestContext.getMessagesReceived()).thenReturn(1);
        when(requestContext.getMessagesSent()).thenReturn(3);
        when(requestContext.getRemoteAddress()).thenReturn("address");
        when(requestContext.getUser()).thenReturn("user");

        assertEquals("user id correlationId address action (>1 <3)", converter.convert(null));
    }

    @Test
    public void testConvertHandlesRequestMissingFields() {
        when(loggerContext.getObject(eq(OBJ_REQUEST_MANAGER))).thenReturn(requestManager);
        when(requestManager.getContext()).thenReturn(Optional.of(requestContext));

        when(requestContext.getId()).thenReturn("id");
        when(requestContext.getRemoteAddress()).thenReturn("address");

        assertEquals("id address (>0 <0)", converter.convert(null));
    }

    @Test
    public void testConvertHandlesRequestWithoutAnyFields() {
        when(loggerContext.getObject(eq(OBJ_REQUEST_MANAGER))).thenReturn(requestManager);
        when(requestManager.getContext()).thenReturn(Optional.of(requestContext));

        assertEquals("- (>0 <0)", converter.convert(null));
    }

    @Test
    public void testConvertWithoutRequestManager() {
        assertEquals("-", converter.convert(null));
    }

    @Test
    public void testConvertWithoutRequest() {
        when(loggerContext.getObject(eq(OBJ_REQUEST_MANAGER))).thenReturn(requestManager);
        when(requestManager.getContext()).thenReturn(Optional.empty());

        assertEquals("-", converter.convert(null));

        verify(loggerContext).getObject(eq(OBJ_REQUEST_MANAGER));
        verify(requestManager).getContext();
    }
}