/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package model.person;

import model.person.enums.TokenType;
import static java.time.temporal.ChronoUnit.MONTHS;
import java.time.Instant;
import java.util.Objects;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.PrePersist;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import model.AbstractEntity;
import model.ticket.Ticket;

/**
 *
 * @author Patrick
 */
@Entity
@Table(name = "token", uniqueConstraints = {
    @UniqueConstraint(columnNames = {"token_hash"})
})
@NamedQueries({
    @NamedQuery(name = Token.REMOVE_TOKEN, query = "DELETE FROM Token t where t.tokenHash = :tokenHash"),
    @NamedQuery(name = Token.REMOVE_EXPIRED_TOKEN, query = "DELETE FROM Token t where t.expiration < :timestamp")
})
public class Token extends AbstractEntity {

    private static final long serialVersionUID = -6632692800064453512L;
    public static final String REMOVE_TOKEN = "Token.removeToken";
    public static final String REMOVE_EXPIRED_TOKEN = "Token.removeExpiredToken";

    @Column(name = "token_hash")
    private String tokenHash;

    @Column(name = "token_type")
    @Enumerated(EnumType.STRING)
    private TokenType tokenType;

    @Column(name = "ip_address", length = 45)
    private String ipAddress;

    private String description;

    private Instant created;

    private Instant expiration;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "account_id")
    private Person person;
    
    @ManyToOne
    private Ticket ticket;

    public Token() {
    }

    @PrePersist
    public void generateInformation() {
        this.created = Instant.now();
        if (this.expiration == null) {
            this.expiration = this.created.plus(1, MONTHS);
        }
    }

    public String getTokenHash() {
        return tokenHash;
    }

    public void setTokenHash(String tokenHash) {
        this.tokenHash = tokenHash;
    }

    public TokenType getTokenType() {
        return tokenType;
    }

    public void setTokenType(TokenType tokenType) {
        this.tokenType = tokenType;
    }

    public String getIpAddress() {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress) {
        this.ipAddress = ipAddress;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Instant getCreated() {
        return created;
    }

    public void setCreated(Instant created) {
        this.created = created;
    }

    public Instant getExpiration() {
        return expiration;
    }

    public void setExpiration(Instant expiration) {
        this.expiration = expiration;
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    /* don't depend on natural identifier for equality checks, see: https://vladmihalcea.com/2017/03/29/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/#more-7143 */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Token token = (Token) obj;
        return Objects.equals(getId(), token.getId());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId());
    }

    @Override
    public String toString() {
        return "Token{ id " + getId() + '}';
    }

    public Ticket getTicket() {
        return ticket;
    }

    public void setTicket(Ticket ticket) {
        this.ticket = ticket;
    }
}
