package eu.dnetlib.lbs.subscriptions;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Table;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import eu.dnetlib.lbs.elasticsearch.Event;

@Entity(name = "subscriptions")
@Table(name = "subscriptions")
public class Subscription {

	@Id
	@Column(name = "subscriptionid")
	private String subscriptionId;

	@Column(name = "subscriber", length = 4096, nullable = false)
	private String subscriber;

	@Column(name = "topic", nullable = false)
	private String topic;

	@Column(name = "frequency", nullable = false)
	@Enumerated(EnumType.STRING)
	private NotificationFrequency frequency;

	@Column(name = "mode", nullable = false)
	@Enumerated(EnumType.STRING)
	private NotificationMode mode;

	@Column(name = "lastNotificationDate", nullable = true)
	private Date lastNotificationDate;

	@Column(name = "creationDate", nullable = false, columnDefinition = "timestamp default '2018-01-01 00:00:00'")
	private Date creationDate;

	@Column(name = "conditions", length = 4096, nullable = true)
	private String conditions;

	public Subscription() {}

	public Subscription(final String subscriptionId, final String subscriber, final String topic, final NotificationFrequency frequency,
			final NotificationMode mode,
			final Date lastNotificationDate, final Date creationDate, final List<MapCondition> conditions) {
		this(subscriptionId, subscriber, topic, frequency, mode, lastNotificationDate, creationDate, new Gson().toJson(conditions));
	}

	public Subscription(final String subscriptionId, final String subscriber, final String topic, final NotificationFrequency frequency,
			final NotificationMode mode, final Date lastNotificationDate, final Date creationDate, final String conditions) {
		this.subscriptionId = subscriptionId;
		this.subscriber = subscriber;
		this.topic = topic;
		this.frequency = frequency;
		this.mode = mode;
		this.lastNotificationDate = lastNotificationDate;
		this.creationDate = creationDate;
		this.conditions = conditions;
	}

	public String getSubscriptionId() {
		return this.subscriptionId;
	}

	public void setSubscriptionId(final String subscriptionId) {
		this.subscriptionId = subscriptionId;
	}

	public String getSubscriber() {
		return this.subscriber;
	}

	public void setSubscriber(final String subscriber) {
		this.subscriber = subscriber;
	}

	public String getTopic() {
		return this.topic;
	}

	public void setTopic(final String topic) {
		this.topic = topic;
	}

	public NotificationFrequency getFrequency() {
		return this.frequency;
	}

	public void setFrequency(final NotificationFrequency frequency) {
		this.frequency = frequency;
	}

	public NotificationMode getMode() {
		return this.mode;
	}

	public void setMode(final NotificationMode mode) {
		this.mode = mode;
	}

	public Date getLastNotificationDate() {
		return this.lastNotificationDate;
	}

	public void setLastNotificationDate(final Date lastNotificationDate) {
		this.lastNotificationDate = lastNotificationDate;
	}

	public Date getCreationDate() {
		return this.creationDate;
	}

	public void setCreationDate(final Date creationDate) {
		this.creationDate = creationDate;
	}

	public String getConditions() {
		return this.conditions;
	}

	public List<MapCondition> getConditionsAsList() {
		return new Gson().fromJson(this.conditions, new TypeToken<List<MapCondition>>() {}.getType());
	}

	public void setConditions(final String conditions) {
		this.conditions = conditions;
	}

	public static boolean isReady(final Subscription s) {
		if (s == null || s.getFrequency() == NotificationFrequency.never) {
			return false;
		} else if (s.getFrequency() == NotificationFrequency.realtime) {
			return true;
		} else if (s.getLastNotificationDate() == null) {
			return true;
		} else {
			final long diff = new Date().getTime() - s.getLastNotificationDate().getTime();
			if (((s.getFrequency() == NotificationFrequency.daily) && (diff >= TimeUnit.DAYS.toMillis(1))) ||
					((s.getFrequency() == NotificationFrequency.weekly) && (diff >= TimeUnit.DAYS.toMillis(7))) ||
					((s.getFrequency() == NotificationFrequency.monthly) && (diff >= TimeUnit.DAYS.toMillis(30)))) { return true; }
		}
		return false;
	}

	@Override
	public String toString() {
		return new Gson().toJson(this);
	}

	public boolean verifyEventConditions(final Event event) {
		for (final MapCondition cond : getConditionsAsList()) {
			if (!cond.verifyEvent(event)) { return false; }
		}
		return true;
	}

}
