package com.atlassian.bitbucket.scm.git.event;

import com.atlassian.event.api.AsynchronousPreferred;
import com.atlassian.bitbucket.event.ApplicationEvent;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.bitbucket.repository.RefChange;
import com.atlassian.bitbucket.repository.Repository;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkNotNull;

/**
 * The Git plugin creates and maintains refs for each pull request. When a pull request is rescoped (either the 'from'
 * or the 'to' branch is updated) the pull request refs are not updated immediately. Often a merge operation will
 * need to be performed to determine the new diff. Merges can be slow and for this reason, pull requests refs are
 * updated asynchronously. When this happens a {@code GitPullRequestRefsChangedEvent} is raised.
 */
@AsynchronousPreferred
public class GitPullRequestRefsChangedEvent extends ApplicationEvent {

    private final RefChange fromRefChange;
    private final RefChange mergeRefChange;
    private final PullRequest pullRequest;

    public GitPullRequestRefsChangedEvent(@Nonnull Object source, @Nonnull PullRequest pullRequest,
                                          @Nullable RefChange fromRefChange, @Nullable RefChange mergeRefChange) {
        super(source);

        this.fromRefChange = fromRefChange;
        this.mergeRefChange = mergeRefChange;
        this.pullRequest = checkNotNull(pullRequest, "pullRequest");
    }

    /**
     * @return the ref change describing how the {@code /pull-requests/id/from} ref has changed. {@code null} if the ref
     *         did not change
     */
    @Nullable
    public RefChange getFromRefChange() {
        return fromRefChange;
    }

    /**
     * @return the ref change describing how the {@code /pull-requests/id/merge} ref has changed. {@code null} if the
     *         ref did not change
     */
    @Nullable
    public RefChange getMergeRefChange() {
        return mergeRefChange;
    }

    /**
     * @return the pull request for which the ref(s) were updated
     */
    @Nonnull
    public PullRequest getPullRequest() {
        return pullRequest;
    }

    /**
     * @return the target repository of the pull request
     */
    @Nonnull
    public Repository getRepository() {
        return pullRequest.getToRef().getRepository();
    }

    /**
     * @return {@code true} if the {@code /pull-requests/id/from} ref has changed
     */
    public boolean hasFromRefChanged() {
        return fromRefChange != null;
    }

    /**
     * @return {@code true} if the {@code /pull-requests/id/merge} ref has changed
     */
    public boolean hasMergeRefChanged() {
        return mergeRefChange != null;
    }
}
