package com.atlassian.stash.internal.plugin.hooks.approvers;

import com.atlassian.bitbucket.i18n.I18nService;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.pull.PullRequestParticipant;
import com.atlassian.bitbucket.repository.Repository;
import com.atlassian.bitbucket.scm.pull.MergeRequest;
import com.atlassian.bitbucket.scm.pull.MergeRequestCheck;
import com.google.common.collect.Iterables;

import javax.annotation.Nonnull;

/**
 * Vetoes any pull request that does not have enough approvers.
 */
public class RequiredApproversMergeCheck implements MergeRequestCheck {

    private final I18nService i18nService;
    private final RequiredApproversHelper helper;

    public RequiredApproversMergeCheck(I18nService i18nService, RequiredApproversHelper helper) {
        this.i18nService = i18nService;
        this.helper = helper;
    }

    @Override
    public void check(@Nonnull MergeRequest mergeRequest) {
        PullRequest pullRequest = mergeRequest.getPullRequest();
        Repository repository = pullRequest.getToRef().getRepository();
        int requiredCount = helper.getRequiredApproversCount(repository);

        if (requiredCount <= 0) {
            return;
        }

        int approvals = countApprovals(pullRequest);
        int needed = requiredCount - approvals;
        if (needed >= 1) {
            veto(mergeRequest, i18nService.getMessage("bitbucket.requiredApprovers.veto.message", needed));
        }
    }

    private int countApprovals(PullRequest pullRequest) {
        int approvals = 0;
        for (PullRequestParticipant reviewer : getAllParticipants(pullRequest)) {
            if (reviewer.isApproved()) {
                approvals++;
            }
        }

        return approvals;
    }

    private Iterable<PullRequestParticipant> getAllParticipants(PullRequest pullRequest) {
        // this relies on the assumption that a participant of a pull request can have only one role,
        // i.e. any individual user can only be either a reviewer (PullRequestRole.REVIEWER) or
        // a 'regular' participant (PullRequestRole.PARTICIPANT).
        return Iterables.concat(pullRequest.getReviewers(), pullRequest.getParticipants());
    }

    private void veto(MergeRequest mergeRequest, String errorMessage) {
        mergeRequest.veto(i18nService.getMessage("bitbucket.build.required.approvers.veto.short.message"), errorMessage);
    }

}
