package com.atlassian.stash.sal.api.auth;

import com.atlassian.bitbucket.license.LicenseService;
import com.atlassian.bitbucket.user.ApplicationUser;
import com.atlassian.sal.api.auth.AuthenticationController;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;

import javax.servlet.http.HttpServletRequest;
import java.security.Principal;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class AuthenticationControllerImplTest {

    private final String fakeUsername = "fake";
    private final String realUsername = "real";
    private final String inactiveUsername = "inactive";

    @Mock
    private AuthenticationContext authenticationContext;

    @Mock
    private LicenseService licenseService;

    private ApplicationUser currentUser;

    @Mock
    private Principal realPrincipal;

    @Mock
    private Principal fakePrincipal;

    @Mock
    private Principal inactivePrincipal;

    @Mock
    private ApplicationUser realUser;

    @Mock
    private ApplicationUser fakeUser;

    @Mock
    private ApplicationUser inactiveUser;

    @Mock
    private HttpServletRequest request;

    private AuthenticationController authenticationController;

    @Before
    public void setUp() throws Exception {
        when(realPrincipal.getName()).thenReturn(realUsername);
        when(fakePrincipal.getName()).thenReturn(fakeUsername);
        when(inactivePrincipal.getName()).thenReturn(inactiveUsername);
        when(realUser.getName()).thenReturn(realUsername);
        when(realUser.isActive()).thenReturn(true);
        when(fakeUser.getName()).thenReturn(fakeUsername);
        when(fakeUser.isActive()).thenReturn(true);
        when(inactiveUser.getName()).thenReturn(inactiveUsername);
        when(inactiveUser.isActive()).thenReturn(false);
        when(authenticationContext.getCurrentUser()).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return currentUser;
            }
        });
        when(licenseService.canLogin(realPrincipal)).thenReturn(true);
        when(licenseService.canLogin(realUser)).thenReturn(true);


        authenticationController = new AuthenticationControllerImpl(authenticationContext, licenseService);
    }

    @Test
    public void testCanLogin() throws Exception {
        assertTrue("principal with name of real user should be able to log in",
                authenticationController.canLogin(realPrincipal, request));
        assertTrue("real user should be able to log in",
                authenticationController.canLogin(realUser, request));

        assertFalse("Handles null", authenticationController.canLogin(null, request));

        assertFalse("fake principal should not be able to log in", authenticationController.canLogin(fakePrincipal, request));
        assertFalse("fake user should not be able to log in", authenticationController.canLogin(fakeUser, request));

        assertFalse("principal with name of fake user should not be able to log in", authenticationController.canLogin(inactivePrincipal, request));
        assertFalse("inactive user should not be able to log in", authenticationController.canLogin(inactiveUser, request));
    }

    @Test
    public void testShouldAttemptAuthentication() throws Exception {
        assertTrue("handles null", authenticationController.shouldAttemptAuthentication(null));
        currentUser = realUser;
        assertFalse("handles null", authenticationController.shouldAttemptAuthentication(null));

        currentUser = null;
        assertTrue("true if there is no current user", authenticationController.shouldAttemptAuthentication(request));
        currentUser = realUser;
        assertFalse("false if there is a current user", authenticationController.shouldAttemptAuthentication(request));
    }
}
