package com.atlassian.stash.internal.idx;

import com.atlassian.stash.internal.repository.InternalRepository;
import org.hibernate.validator.constraints.NotEmpty;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;

/**
 * Entity to record when a {@code CommitIndexer} last indexed a repository.
 */
@Entity
@Table(name = InternalIndexerState.TABLE)
@IdClass(InternalIndexerState.PK.class)
public class InternalIndexerState {
    public static final String TABLE = "cs_indexer_state";

    @Column(name = "indexer_id") @NotEmpty
    @Id
    private final String indexerId;

    @Id
    @JoinColumn(name = "repository_id")
    @ManyToOne(fetch = FetchType.LAZY)
    private final InternalRepository repository;

    @Column(name = "last_run")
    private final Long lastRun; // stored as a long because mysql stores timestamps is seconds precision
    
    // for hibernate
    protected InternalIndexerState() {
        this.indexerId = null;
        this.repository = null;
        this.lastRun = null;
    }

    public InternalIndexerState(@Nonnull String indexerId, @Nonnull InternalRepository repository, @Nullable Long lastRun) {
        this.indexerId = indexerId;
        this.repository = repository;
        this.lastRun = lastRun;
    }

    public String getIndexerId() {
        return indexerId;
    }

    public InternalRepository getRepository() {
        return repository;
    }
    
    public Long getLastRun() {
        return lastRun;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o instanceof InternalIndexerState) {
            InternalIndexerState that = (InternalIndexerState) o;

            return Objects.equals(getIndexerId(), that.getIndexerId()) &&
                    Objects.equals(getRepository(), that.getRepository());
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(getIndexerId(), getRepository());
    }

    public static class PK implements Serializable {

        private final String indexerId;
        private final int repository;

        @SuppressWarnings("unused") // for hibernate
        private PK() {
            this(null, 0);
        }

        public PK(String indexerId, int repository) {
            this.indexerId = indexerId;
            this.repository = repository;
        }

        public String getIndexerId() {
            return indexerId;
        }

        public int getRepositoryId() {
            return repository;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            PK pk = (PK) o;

            return indexerId.equals(pk.indexerId) && repository == pk.repository;
        }

        @Override
        public int hashCode() {
            int result = indexerId.hashCode();
            result = 31 * result + repository;
            return result;
        }
    }
}
