package com.atlassian.stash.internal.auth;

import com.atlassian.event.api.EventPublisher;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.bitbucket.auth.HttpAuthenticationSuccessHandler;
import com.atlassian.bitbucket.auth.HttpAuthenticationSuccessHandlerModuleDescriptor;
import com.atlassian.bitbucket.event.auth.AuthenticationSuccessEvent;
import com.atlassian.bitbucket.plugin.ModuleDescriptorTestUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static org.junit.Assert.*;
import static org.mockito.Matchers.same;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class PluginHttpAuthenticationSuccessHandlerTest {

    @Mock
    PluginAccessor accessor;
    @Mock
    DefaultHttpAuthenticationContext context;
    @Mock
    EventPublisher eventPublisher;
    @Mock
    HttpAuthenticationSuccessHandler handler1;
    @Mock
    HttpAuthenticationSuccessHandler handler2;
    @InjectMocks
    PluginHttpAuthenticationSuccessHandler handler;

    @Before
    public void setUp() {
        when(context.getMethod()).thenReturn("method");
        when(context.getUsername()).thenReturn("username");
    }

    @Test
    public void testEventPublished() throws Exception {
        mockPluginAccessor(handler1, handler2);

        handler.onAuthenticationSuccess(context);

        ArgumentCaptor<AuthenticationSuccessEvent> eventCaptor = ArgumentCaptor.forClass(AuthenticationSuccessEvent.class);
        verify(eventPublisher).publish(eventCaptor.capture());

        AuthenticationSuccessEvent event = eventCaptor.getValue();
        assertEquals("method", event.getAuthenticationMethod());
        assertEquals("username", event.getUsername());
    }

    @Test
    public void testAllModulesConsidered() throws Exception {
        mockPluginAccessor(handler1, handler2);

        assertFalse(handler.onAuthenticationSuccess(context));
        verify(handler1).onAuthenticationSuccess(same(context));
        verify(handler2).onAuthenticationSuccess(same(context));
    }

    @Test
    public void testNoModulesReturnsFalse() throws Exception {
        // mock without modules
        mockPluginAccessor();

        assertFalse(handler.onAuthenticationSuccess(context));
    }

    @Test
    public void testProcessingStopsOnFirstModule() throws Exception {
        mockPluginAccessor(handler1, handler2);
        when(handler1.onAuthenticationSuccess(same(context))).thenReturn(true);

        assertTrue(handler.onAuthenticationSuccess(context));
        verify(handler1).onAuthenticationSuccess(same(context));
        verify(handler2, never()).onAuthenticationSuccess(same(context));
    }

    private void mockPluginAccessor(HttpAuthenticationSuccessHandler... handlers) {
        ModuleDescriptorTestUtils.mockWeightedModuleDescriptors(
                accessor, HttpAuthenticationSuccessHandlerModuleDescriptor.class, handlers);
    }
    
}
