package com.atlassian.bitbucket.web.conditions;

import com.atlassian.stash.internal.project.InternalNormalProject;
import com.atlassian.stash.internal.project.InternalPersonalProject;
import com.atlassian.stash.internal.user.InternalNormalUser;
import com.atlassian.bitbucket.project.ProjectVisitor;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.auth.AuthenticationContext;
import org.junit.Before;
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.Collections;
import java.util.Map;

import static com.atlassian.bitbucket.web.conditions.IsPersonalRepositoryCondition.ONLY_MINE;
import static com.atlassian.bitbucket.web.conditions.IsPersonalRepositoryCondition.REPOSITORY;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class IsPersonalRepositoryConditionTest {

    private static final Map<String, String> ONLY_MINE_PARAMS = Collections.singletonMap(ONLY_MINE, "true");
    private static final Map<String, String> EMPTY_PARAMS = Collections.emptyMap();
    private static final Map<String, Object> EMPTY_CONTEXT = Collections.emptyMap();

    @Mock
    private AuthenticationContext authenticationContext;
    @Mock
    private InternalNormalProject project;
    @Mock
    private InternalPersonalProject personalProject;
    @Mock
    private Repository repo;
    @Mock
    private Repository personalRepo;
    @Mock
    private InternalNormalUser currentUser;
    @Mock
    private InternalNormalUser otherUser;

    @InjectMocks
    private IsPersonalRepositoryCondition condition;

    private Map<String, Object> personalContext;
    private Map<String, Object> nonpersonalContext;

    @Before
    public void setup() throws Exception {
        personalContext = Collections.<String, Object>singletonMap(REPOSITORY, personalRepo);
        nonpersonalContext = Collections.<String, Object>singletonMap(REPOSITORY, repo);

        when(currentUser.getName()).thenReturn("Ada");
        when(otherUser.getName()).thenReturn("Turing");

        when(repo.getProject()).thenReturn(project);
        when(personalRepo.getProject()).thenReturn(personalProject);

        when(project.accept(isA(ProjectVisitor.class))).thenCallRealMethod();
        when(personalProject.accept(isA(ProjectVisitor.class))).thenCallRealMethod();
    }

    @Test
    public void testSucceedsOnMyProject() throws Exception {
        init(currentUser, currentUser, EMPTY_PARAMS);
        assertTrue(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testSucceedsOnAnonymous() throws Exception {
        init(null, otherUser, EMPTY_PARAMS);
        assertTrue(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testSucceedsOnOtherOwner() throws Exception {
        init(currentUser, otherUser, EMPTY_PARAMS);
        assertTrue(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testFailsOnNonPersonal() throws Exception {
        init(currentUser, null, EMPTY_PARAMS);
        assertFalse(condition.shouldDisplay(nonpersonalContext));
    }

    @Test
    public void testFailsOnNoProject() throws Exception {
        init(currentUser, null, EMPTY_PARAMS);
        assertFalse(condition.shouldDisplay(EMPTY_CONTEXT));
    }

    @Test
    public void testOnlyMyProjectSucceedsOnMyProject() throws Exception {
        init(currentUser, currentUser, ONLY_MINE_PARAMS);
        assertTrue(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testOnlyMyProjectFailsOnAnonymous() throws Exception {
        init(null, otherUser, ONLY_MINE_PARAMS);
        assertFalse(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testOnlyMyProjectFailsOnOtherOwner() throws Exception {
        init(currentUser, otherUser, ONLY_MINE_PARAMS);
        assertFalse(condition.shouldDisplay(personalContext));
    }

    @Test
    public void testOnlyMyProjectFailsOnNonPersonal() throws Exception {
        init(currentUser, null, ONLY_MINE_PARAMS);
        assertFalse(condition.shouldDisplay(nonpersonalContext));
    }

    @Test
    public void testOnlyMyProjectFailsOnNoProject() throws Exception {
        init(currentUser, null, ONLY_MINE_PARAMS);
        assertFalse(condition.shouldDisplay(EMPTY_CONTEXT));
    }

    private void init(InternalNormalUser currentUser, InternalNormalUser owner, Map<String, String> params) {
        when(authenticationContext.getCurrentUser()).thenReturn(currentUser);
        when(personalProject.getOwner()).thenReturn(owner);
        condition.init(params);
    }
}
