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

import com.atlassian.stash.internal.ApplicationConstants;
import com.atlassian.stash.internal.HibernateUtils;
import com.atlassian.stash.internal.Initializable;
import com.atlassian.stash.internal.pull.InternalPullRequest;
import com.atlassian.bitbucket.validation.annotation.RequiredString;

import javax.persistence.*;

/**
 * Entity for keeping track of pending comment drift operations. The comment drift calculations are managed through an
 * in-memory queue. The contents of this queue is persisted in database to ensure that application restarts do not lead
 * to inconsistent state (drift calculations that were pending being lost because of the shutdown).
 *
 * @since 1.3
 */
@Entity
@Table(name = InternalDriftRequest.TABLE)
public class InternalDriftRequest implements Initializable {

    private static final String ID_GEN = "driftRequestIdGenerator";
    static final String TABLE = "sta_drift_request";

    @TableGenerator(name = ID_GEN, table = ApplicationConstants.ID_SEQUENCE_TABLE, pkColumnValue = TABLE, allocationSize = 10)
    @Id @GeneratedValue(generator = ID_GEN, strategy = GenerationType.TABLE)
    @Column(name = "id", nullable = false, unique = true)
    private final Long id;

    @Column(name = "new_from_hash", nullable = false)
    @RequiredString(minimumSize = 40, size = 40)
    private final String newFromHash;

    @Column(name = "new_to_hash", nullable = false)
    @RequiredString(minimumSize = 40, size = 40)
    private final String newToHash;

    @Column(name = "old_from_hash", nullable = false)
    @RequiredString(minimumSize = 40, size = 40)
    private final String oldFromHash;

    @Column(name = "old_to_hash", nullable = false)
    @RequiredString(minimumSize = 40, size = 40)
    private final String oldToHash;

    @JoinColumn(name = "pr_id", nullable = false, foreignKey = @ForeignKey(name = "fk_sta_drift_request_pr"))
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private final InternalPullRequest pullRequest;

    @Column(name = "attempts", nullable = false)
    private final int attempts;

    // for Hibernate
    protected InternalDriftRequest() {
        this.id = null;
        this.oldFromHash = this.oldToHash = this.newFromHash = this.newToHash = null;
        this.pullRequest = null;
        this.attempts = 0;
    }

    public InternalDriftRequest(Long id, InternalPullRequest pullRequest, String oldFromHash, String oldToHash,
                                String newFromHash, String newToHash) {
        this.id = id;
        this.newFromHash = newFromHash;
        this.newToHash = newToHash;
        this.oldFromHash = oldFromHash;
        this.oldToHash = oldToHash;
        this.pullRequest = pullRequest;
        this.attempts = 0;
    }

    public Long getId() {
        return id;
    }

    public String getNewFromHash() {
        return newFromHash;
    }

    public String getNewToHash() {
        return newToHash;
    }

    public String getOldFromHash() {
        return oldFromHash;
    }

    public String getOldToHash() {
        return oldToHash;
    }

    public int getAttempts() {
        return attempts;
    }

    public InternalPullRequest getPullRequest() {
        return pullRequest;
    }

    public void initialize() {
        HibernateUtils.initialize(getPullRequest());
    }

    @Override
    public String toString() {
        InternalPullRequest pullRequest = getPullRequest();

        return pullRequest.getScopeRepository().getId() + ":" + pullRequest.getId() + "@" +
                pullRequest.getVersion() + " (" + getOldFromHash() + ", " + getOldToHash() +
                ") -> (" + getNewFromHash() + ", " + getNewToHash() + ")";
    }
}
