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

import com.atlassian.bitbucket.internal.branch.model.BranchModelNode;
import com.atlassian.bitbucket.repository.Branch;
import org.hamcrest.FeatureMatcher;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

import javax.annotation.Nonnull;

import static org.hamcrest.Matchers.*;

public class BranchModelNodeMatchers {

    private BranchModelNodeMatchers() {
        throw new UnsupportedOperationException(BranchModelNodeMatchers.class.getName() + " should not be instantiated");
    }

    public static Matcher<BranchModelNode> isLeaf() {
        return isLeaf(true);
    }

    public static Matcher<BranchModelNode> isLeaf(boolean isLeaf) {
        return new FeatureMatcher<BranchModelNode, Boolean>(is(isLeaf), "is leaf node", "isLeaf") {
            @Override
            protected Boolean featureValueOf(@Nonnull BranchModelNode actual) {
                return actual.isLeaf();
            }
        };
    }

    public static Matcher<BranchModelNode> isLeafWithBranchThat(Matcher<Branch> branchMatcher) {
        return allOf(isLeaf(), withBranchThat(branchMatcher));
    }

    @SafeVarargs
    public static Matcher<BranchModelNode> isSinglePath(Matcher<Branch>... pathMatchers) {
        Matcher<BranchModelNode> answer = withBranchThat(pathMatchers[pathMatchers.length - 1]);
        for (int i = pathMatchers.length - 2; i > -1; --i) {
            answer = Matchers.allOf(withBranchThat(pathMatchers[i]), withDownstreamThat(contains(answer)));
        }
        return answer;
    }

    public static Matcher<BranchModelNode> withBranchThat(Matcher<Branch> branchMatcher) {
        return new FeatureMatcher<BranchModelNode, Branch>(branchMatcher, "with branch that", "branch") {
            @Override
            protected Branch featureValueOf(BranchModelNode actual) {
                return actual.getBranch();
            }
        };
    }

    public static Matcher<BranchModelNode> withDownstreamThat(Matcher<? super Iterable<? extends BranchModelNode>> downstreamMatcher) {
        return new FeatureMatcher<BranchModelNode, Iterable<BranchModelNode>>(downstreamMatcher, "with downstream that", "downstream") {
            @Override
            protected Iterable<BranchModelNode> featureValueOf(BranchModelNode actual) {
                return actual.getDownstream();
            }
        };
    }

}
