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

import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.repository.ref.restriction.RefMatcher;
import com.atlassian.bitbucket.user.ApplicationUser;

import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Objects;

import static java.util.Objects.requireNonNull;

/**
 * The details about a pull request required to determine who should be listed as a default reviewer.
 *
 * @since 1.0
 */
public class DefaultPullRequestCondition implements PullRequestCondition {
    private final RefMatcher fromMatcher;
    private final RefMatcher toMatcher;
    private final Repository repository;
    private final int requiredApprovals;
    private final Collection<ApplicationUser> reviewers;
    private final int id;

    private DefaultPullRequestCondition(Builder builder) {
        id = requireNonNull(builder.id);
        repository = requireNonNull(builder.repository);
        fromMatcher = requireNonNull(builder.fromMatcher);
        toMatcher = requireNonNull(builder.toMatcher);
        requiredApprovals = requireNonNull(builder.requiredApprovals);
        reviewers = requireNonNull(builder.reviewers);
    }

    public static Builder builder() {
        return new Builder();
    }

    public RefMatcher getFromMatcher() {
        return fromMatcher;
    }

    public RefMatcher getToMatcher() {
        return toMatcher;
    }

    public Repository getRepository() {
        return repository;
    }

    @Override
    public Collection<ApplicationUser> getReviewers() {
        return reviewers;
    }

    @Override
    public int getRequiredApprovals() {
        return requiredApprovals;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, repository, fromMatcher, toMatcher, reviewers, requiredApprovals);
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof PullRequestCondition)) {
            return false;
        }

        PullRequestCondition that = (PullRequestCondition) other;
        return this.getId() == that.getId()
                && this.getRepository().equals(that.getRepository())
                && this.getFromMatcher().equals(that.getFromMatcher())
                && this.getToMatcher().equals(that.getToMatcher())
                && this.getReviewers().equals(that.getReviewers())
                && this.getRequiredApprovals() == that.getRequiredApprovals();
    }

    public static final class Builder {
        private RefMatcher fromMatcher;
        private RefMatcher toMatcher;
        private Repository repository;
        private Collection<ApplicationUser> reviewers;
        private Integer requiredApprovals;
        public Integer id = 0;

        private Builder() {
        }

        @Nonnull
        public Builder id(int id) {
            this.id = id;
            return this;
        }

        @Nonnull
        public Builder sourceMatcher(@Nonnull RefMatcher sourceMatcher) {
            fromMatcher = requireNonNull(sourceMatcher);
            return this;
        }

        @Nonnull
        public Builder targetMatcher(@Nonnull RefMatcher targetMatcher) {
            toMatcher = requireNonNull(targetMatcher);
            return this;
        }

        @Nonnull
        public Builder repository(@Nonnull Repository repository) {
            this.repository = requireNonNull(repository);
            return this;
        }

        @Nonnull
        public Builder requiredApprovals(Integer requiredApprovals) {
            this.requiredApprovals = requireNonNull(requiredApprovals);
            return this;
        }

        @Nonnull
        public Builder reviewers(@Nonnull Collection<ApplicationUser> reviewers) {
            this.reviewers = requireNonNull(reviewers);
            return this;
        }

        @Nonnull
        public DefaultPullRequestCondition build() {
            return new DefaultPullRequestCondition(this);
        }
    }
}
