package com.atlassian.stash.internal.pull.comment.diff;

import com.atlassian.bitbucket.content.SimpleDiff;
import com.atlassian.bitbucket.content.SimpleDiffHunk;
import com.atlassian.stash.internal.comment.InternalComment;
import com.atlassian.stash.internal.comment.InternalDiffCommentAnchor;
import com.atlassian.stash.internal.pull.InternalPullRequestCommentActivity;
import com.atlassian.bitbucket.property.PropertyMap;
import org.apache.commons.lang3.StringUtils;

import javax.annotation.Nonnull;

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

/**
 * A comment on a line in a diff, suitable for applying {@link DiffContext context}.
 */
public class DiffComment {

    private final InternalPullRequestCommentActivity activity;
    private final InternalDiffCommentAnchor anchor;
    private final InternalComment comment;
    private final PropertyMap properties;

    /**
     * Constructs a new {@code DiffComment} from the {@link InternalComment comment} and
     * {@link InternalDiffCommentAnchor anchor} contained in the provided
     * {@link InternalPullRequestCommentActivity activity}.
     * <p>
     * If the {@link #isAnchoredOn(DiffContextLine) anchor} for the comment is found, {@link DiffContext diff context}
     * will be {@link #applyDiff(SimpleDiffHunk) applied} to the provided activity.
     *
     * @param activity an activity containing both a comment and its anchor
     * @param properties the properties to apply to the diff
     * @throws NullPointerException if the provided activity is {@code null} or if it does not include an anchor
     */
    public DiffComment(@Nonnull InternalPullRequestCommentActivity activity,
                       @Nonnull PropertyMap properties) {
        this.activity = checkNotNull(activity, "An activity is required");
        this.properties = checkNotNull(properties, "properties");

        anchor = checkNotNull(activity.getCommentAnchor(), "Only anchored comments support gathering context");
        comment = activity.getComment();
    }

    /**
     * Creates a {@link SimpleDiff diff} containing the provided {@link SimpleDiffHunk hunk} and applies it to
     * the {@link InternalPullRequestCommentActivity activity} set during construction.
     *
     * @param hunk the hunk containing the diff context for this comment
     */
    public void applyDiff(@Nonnull SimpleDiffHunk hunk) {
        SimpleDiff.Builder diffBuilder = new SimpleDiff.Builder()
                .destination(anchor.getPath())
                .hunk(hunk)
                .properties(properties);
        if (StringUtils.isNotBlank(anchor.getSrcPath())) {
            diffBuilder.source(anchor.getSrcPath());
        }
        activity.setDiff(diffBuilder.build());
    }

    /**
     * Retrieves the ID for this comment.
     *
     * @return the comment's ID
     */
    public long getId() {
        return comment.getId();
    }

    /**
     * Retrieves a flag indicating whether {@link DiffContext diff context} has been
     * {@link #applyDiff(SimpleDiffHunk) applied} to this comment.
     *
     * @return {@code true} if a diff has been applied; otherwise, {@code false}
     */
    public boolean isDiffApplied() {
        return activity.getDiff() != null;
    }

    /**
     * Retrieves a flag indicating whether this comment is anchored on the specified {@link DiffContextLine line}.
     *
     * @param line the line to test against this comment's anchor
     * @return {@code true} if this comment is anchored on the specified line; otherwise {@code false}
     * @see DiffContextLine#isAnchor(InternalDiffCommentAnchor)
     */
    public boolean isAnchoredOn(@Nonnull DiffContextLine line) {
        return line.isAnchor(anchor);
    }
}
