package eu.dnetlib.broker.common.topics;

import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;

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

import org.apache.commons.lang3.StringUtils;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;

import eu.dnetlib.broker.common.elasticsearch.Event;

@Entity(name = "topic_types")
@Table(name = "topic_types")
public class TopicType {

	@Id
	@Column(name = "id")
	private String id;

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

	@Column(name = "expression", unique = true, nullable = false)
	private String expression;

	@Column(name = "regex", unique = true, nullable = false)
	private String regex;

	@Column(name = "producerId")
	private String producerId;

	@Column(name = "mapKeys")
	private String mapKeys;

	public TopicType() {}

	public TopicType(final String id, final String name, final String expression, final String producerId, final String mapKeys) {
		this.id = id;
		this.name = name;
		this.expression = expression;
		this.producerId = producerId;
		this.mapKeys = mapKeys;
		updateRegex();
	}

	public TopicType(final String id, final String name, final String expression, final String producerId, final Set<String> mapKeys) {
		this(id, name, expression, producerId, Joiner.on(",").join(mapKeys));
	}

	public String getId() {
		return this.id;
	}

	public void setId(final String id) {
		this.id = id;
	}

	public String getName() {
		return this.name;
	}

	public void setName(final String name) {
		this.name = name;
	}

	public String getProducerId() {
		return this.producerId;
	}

	public void setProducerId(final String producerId) {
		this.producerId = producerId;
	}

	public String getMapKeys() {
		return this.mapKeys;
	}

	public void setMapKeys(final Set<String> mapKeys) {
		this.mapKeys = Joiner.on(",").join(mapKeys);
	}

	public Set<String> getMapKeysAsSet() {
		return Sets.newHashSet(Splitter.on(",").trimResults().omitEmptyStrings().split(this.mapKeys));
	}

	public void setMapKeys(final String mapKeys) {
		this.mapKeys = mapKeys;
	}

	public String getExpression() {
		return this.expression;
	}

	public void setExpression(final String expression) {
		this.expression = expression;
		updateRegex();
	}

	private void updateRegex() {
		this.regex = "^" + this.expression.replaceAll("<[a-zA-Z0-9._-]+>", "[a-zA-Z0-9._-]+").replaceAll("\\/", "\\\\/").trim() + "$";
	}

	public String getRegex() {
		return this.regex;
	}

	public Predicate<Event> asValidator() {
		final Predicate<String> p = Pattern.compile(getRegex()).asPredicate();
		final Set<String> keys = getMapKeysAsSet();
		return e -> e != null
			&& StringUtils.isNotBlank(e.getTopic())
			&& p.test(e.getTopic())
			&& (StringUtils.isBlank(TopicType.this.producerId) ||
				TopicType.this.producerId.equals(e.getProducerId()))
			&& e.getMap().keySet().containsAll(keys);
	}

}
