package eu.dnetlib.broker.common.metrics;

import java.util.List;
import java.util.stream.StreamSupport;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import eu.dnetlib.broker.common.elasticsearch.NotificationRepository;
import eu.dnetlib.broker.common.stats.OpenaireDsStatRepository;
import eu.dnetlib.broker.common.subscriptions.ConditionOperator;
import eu.dnetlib.broker.common.subscriptions.MapCondition;
import eu.dnetlib.broker.common.subscriptions.Subscription;
import eu.dnetlib.broker.common.subscriptions.SubscriptionRepository;

@Component
public class MetricsCacheUtils {

	public static final String metrics_cache = "broker_metrics_cache";

	private static final long interval = 12 * 60 * 60 * 1000; // 12 hours

	private static final Log log = LogFactory.getLog(MetricsCacheUtils.class);

	@Autowired
	private SubscriptionRepository subscriptionRepository;

	@Autowired
	private OpenaireDsStatRepository openaireDsStatRepository;

	@Autowired
	private NotificationRepository notificationRepository;

	@Scheduled(fixedDelay = interval, initialDelay = 500)
	@CacheEvict(allEntries = true, value = metrics_cache)
	public void reportCacheEvict() {
		log.debug("Flush Cache: " + metrics_cache);
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double totalEvents() {
		log.debug("Call to cached method: totalEvents()");
		return openaireDsStatRepository.totalEvents();
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double countDatasourcesWithEvents() {
		log.debug("Call to cached method: countDatasourcesWithEvents()");
		return openaireDsStatRepository.countDatasourcesWithEvents();
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double countNotifications() {
		log.debug("Call to cached method: countNotifications()");
		return notificationRepository.count();
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double countSubscriptions() {
		log.debug("Call to cached method: countSubscriptions()");
		return subscriptionRepository.count();
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double countSubscribers() {
		log.debug("Call to cached method: countSubscribers()");
		return subscriptionRepository.countSubscribers();
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double lastUpdateInSeconds() {
		log.debug("Call to cached method: lastUpdateInSeconds()");
		return System.currentTimeMillis() / 1000;
	}

	@Cacheable(value = MetricsCacheUtils.metrics_cache, key = "#root.methodName")
	public double countDatasourcesWithSubscriptions() {
		log.debug("Call to cached method: countDatasourcesWithSubscriptions()");
		return StreamSupport.stream(subscriptionRepository.findAll().spliterator(), false)
			.map(Subscription::getConditionsAsList)
			.flatMap(List::stream)
			.filter(c -> c.getField().equals("targetDatasourceName"))
			.filter(c -> c.getOperator() == ConditionOperator.EXACT)
			.map(MapCondition::getListParams)
			.filter(l -> !l.isEmpty())
			.map(l -> l.get(0).getValue())
			.filter(StringUtils::isNotBlank)
			.distinct()
			.count();
	}

}
