package com.atlassian.bitbucket.internal.branch.model;

import com.atlassian.bitbucket.repository.*;
import com.atlassian.bitbucket.util.Page;
import com.atlassian.bitbucket.util.PageRequest;
import com.atlassian.bitbucket.util.PageUtils;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import static com.atlassian.bitbucket.hamcrest.PageMatchers.isPageOf;
import static com.atlassian.bitbucket.hamcrest.RepositoryMatchers.isBranchWithDisplayId;
import static com.atlassian.bitbucket.internal.branch.model.BranchTypes.*;
import static com.atlassian.bitbucket.mockito.PageAnswer.withLastPageOf;
import static com.atlassian.bitbucket.mockito.PageAnswer.withPageOf;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;

@RunWith(MockitoJUnitRunner.class)
public class PrefixBranchClassifierTest {

    @Mock
    private RefService refService;
    @Mock
    private Repository repository;

    @Test
    public void testGetTypeMatchingTypeFound() {
        InternalBranchType type = createClassifier().getType(newBranch("feature/blah"));
        assertNotNull(type);
        assertEquals(FEATURE.getId(), type.getId());
    }

    @Test
    public void testGetTypeNoMatchingPrefixFound() {
        assertNull(createClassifier().getType(newBranch("/feature/blah")));
    }

    @Test
    public void testGetBranchesFirstPageFull() {
        PageRequest pageRequest = PageUtils.newRequest(0, 3);
        when(refService.getBranches(any(RepositoryBranchesRequest.class), any(PageRequest.class)))
                .thenAnswer(withLastPageOf(
                        newBranch("feature/one"),
                        newBranch("feature/two"),
                        newBranch("feature/three")));

        Page<Branch> result = createClassifier().getBranchesByType(newBranchType(FEATURE, "feature/"), pageRequest);

        assertThat(result, isPageOf(isBranchWithDisplayId("feature/one"),
                isBranchWithDisplayId("feature/two"),
                isBranchWithDisplayId("feature/three")
        ));
    }

    @Test
    public void testGetBranchesNotEnoughResults() {
        when(refService.getBranches(any(RepositoryBranchesRequest.class), any(PageRequest.class)))
                .thenAnswer(withPageOf(
                        newBranch("/feature/one"),
                        newBranch("feature/one"),
                        newBranch("/feature/two"),
                        newBranch("feature/two"),
                        newBranch("/feature/three"),
                        newBranch("feature/three")))
                .thenAnswer(withLastPageOf(
                        newBranch("/feature/four"),
                        newBranch("feature/four"),
                        newBranch("/feature/five"),
                        newBranch("feature/five"),
                        newBranch("/feature/six")));

        Page<Branch> result = createClassifier().getBranchesByType(newBranchType(FEATURE, "feature/"), PageUtils.newRequest(3, 6));

        assertThat(result, isPageOf(isBranchWithDisplayId("feature/one"),
                isBranchWithDisplayId("feature/two"),
                isBranchWithDisplayId("feature/three"),
                isBranchWithDisplayId("feature/four"),
                isBranchWithDisplayId("feature/five")
        ));
    }

    private PrefixBranchClassifier createClassifier() {
        return new PrefixBranchClassifier(refService, repository, ImmutableSet.of(
                newBranchType(BUGFIX, "bugfix/"),
                newBranchType(FEATURE, "feature/"),
                newBranchType(HOTFIX, "hotfix/"),
                newBranchType(RELEASE, "release/")
        ));
    }

    private Branch newBranch(String displayId) {
        return new SimpleBranch.Builder().displayId(displayId).id(displayId).build();
    }

    private InternalBranchType newBranchType(BranchTypes type, String prefix) {
        return newBranchType(type.getId(), prefix);
    }

    private InternalBranchType newBranchType(String id, String prefix) {
        return new SimpleInternalBranchType(BranchTypes.forId(id), id, prefix);
    }
}
