package com.atlassian.stash.internal.user;

import com.atlassian.crowd.embedded.api.User;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Arrays;
import java.util.List;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

@RunWith(MockitoJUnitRunner.class)
@SuppressWarnings({"ConstantConditions", "unchecked"})
public class DefaultUserHelperTest {

    @InjectMocks
    private DefaultUserHelper helper;
    @Mock
    private StashUserDao userDao;

    @Test
    public void testTransformPage() {
        User first = mock(User.class);
        when(first.getName()).thenReturn("first");

        User second = mock(User.class);
        when(second.getName()).thenReturn("second");

        User third = mock(User.class);
        when(third.getName()).thenReturn("third");

        User fourth = mock(User.class);
        when(fourth.getName()).thenReturn("fourth");

        InternalNormalUser firstStashUser = mock(InternalNormalUser.class);
        when(firstStashUser.getName()).thenReturn("first");

        InternalNormalUser secondStashUser = mock(InternalNormalUser.class);
        when(secondStashUser.getName()).thenReturn("second");

        InternalNormalUser fourthStashUser = mock(InternalNormalUser.class);
        when(fourthStashUser.getName()).thenReturn("fourth");

        when(userDao.loadUsers(anySet())).thenReturn(Sets.newHashSet(firstStashUser, secondStashUser, fourthStashUser));

        // third user is missing and should be created on the fly
        InternalNormalUser thirdStashUser = mock(InternalNormalUser.class);
        when(thirdStashUser.getName()).thenReturn("third");
        when(userDao.createFor(third)).thenReturn(thirdStashUser);


        Page<InternalNormalUser> page = helper.transformOrCreate(
                PageUtils.createPage(Arrays.asList(second, first, third, fourth), PageUtils.newRequest(0, 1000)));
        assertNotNull(page);
        assertEquals(4, page.getSize()); //Should not have dropped the un-found user
        assertTrue(page.getIsLastPage());

        //Verify that the order of the transformed page is preserved
        List<InternalNormalUser> users = ImmutableList.copyOf(page.getValues());
        assertEquals("second", users.get(0).getName());
        assertEquals("first", users.get(1).getName());
        assertEquals("third", users.get(2).getName());
        verify(userDao).createFor(third); //User "third" should be created on the fly
        assertEquals("fourth", users.get(3).getName());
    }

    @Test(expected = NullPointerException.class)
    public void testTransformPageWithNull() {
        helper.transformOrCreate((Page) null);
    }

    @Test
    public void testTransformUser() {
        User user = mock(User.class);

        InternalNormalUser stashUser = mock(InternalNormalUser.class);

        when(userDao.loadUser(same(user))).thenReturn(stashUser);

        assertSame(stashUser, helper.transformOrCreate(user));
    }

    @Test
    public void testTransformUserWithNoStashUser() {
        User user = mock(User.class);
        when(user.getName()).thenReturn("jdoe");
        InternalNormalUser createdUser = mock(InternalNormalUser.class);
        when(userDao.createFor(user)).thenReturn(createdUser);

        InternalApplicationUser stashUser = helper.transformOrCreate(user);
        assertSame(createdUser, stashUser);
        verify(userDao).createFor(user);
    }

    @Test(expected = NullPointerException.class)
    public void testTransformUserWithNull() {
        helper.transformOrCreate((User) null);
    }
}
