package com.atlassian.stash.internal.commit;

import com.atlassian.bitbucket.commit.CommitDiscussionCommentAnchor;
import com.atlassian.bitbucket.pull.PullRequest;
import com.atlassian.stash.internal.HibernateUtils;
import com.atlassian.stash.internal.comment.DiffCommentAnchorType;
import com.atlassian.stash.internal.comment.InternalDiffCommentAnchor;
import com.atlassian.stash.internal.pull.InternalPullRequest;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.*;
import java.util.Optional;

import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;

/**
 * @since 2.11
 */
@DiscriminatorValue(DiffCommentAnchorType.COMMIT_DISCUSSION_DISCRIMINATOR)
@Entity
@PrimaryKeyJoinColumn(name = "anchor_id", referencedColumnName = "id",
        foreignKey = @ForeignKey(name = "fk_sta_cmt_disc_com_anc_id"))
@Table(name = InternalCommitDiscussionCommentAnchor.TABLE, indexes = {
        @Index(name = "idx_sta_cmt_com_anc_disc", columnList = "discussion_id"),
        @Index(name = "idx_sta_cmt_com_anc_pr", columnList = "pr_id")
})
public class InternalCommitDiscussionCommentAnchor
        extends InternalDiffCommentAnchor
        implements CommitDiscussionCommentAnchor {

    public static final String TABLE = "sta_cmt_disc_comment_anchor";

    @JoinColumn(name = "discussion_id", nullable = false, foreignKey = @ForeignKey(name = "fk_sta_cmt_disc_com_anc_disc"), updatable = false)
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private final InternalCommitDiscussion discussion;
    @JoinColumn(name = "pr_id", foreignKey = @ForeignKey(name = "fk_sta_pr_com_anc_disc"), updatable = false)
    @ManyToOne(fetch = FetchType.LAZY)
    private final InternalPullRequest pullRequest;

    protected InternalCommitDiscussionCommentAnchor() {
        discussion = null;
        pullRequest = null;
    }

    private InternalCommitDiscussionCommentAnchor(Builder builder) {
        super(builder);

        discussion = builder.discussion;
        pullRequest = builder.pullRequest;
    }

    @Nonnull
    @Override
    public InternalCommitDiscussion getDiscussion() {
        return discussion;
    }

    @Override
    public void initialize() {
        super.initialize();

        getPullRequest().ifPresent(HibernateUtils::initialize);
    }

    @Nonnull
    @Override
    public Optional<PullRequest> getPullRequest() {
        return ofNullable(pullRequest);
    }

    public static class Builder extends AbstractBuilder<Builder, InternalCommitDiscussionCommentAnchor> {

        private final InternalCommitDiscussion discussion;
        private InternalPullRequest pullRequest;

        public Builder(@Nonnull InternalCommitDiscussion discussion) {
            this.discussion = requireNonNull(discussion, "discussion");
        }

        public Builder(@Nonnull InternalCommitDiscussionCommentAnchor anchor) {
            super(anchor);

            this.discussion = anchor.getDiscussion();
        }

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

        @Nonnull
        public Builder pullRequest(@Nullable InternalPullRequest value) {
            pullRequest = value;

            return self();
        }

        @Nonnull
        @Override
        protected Builder self() {
            return this;
        }
    }
}
