package eu.dnetlib.lbs.controllers;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import eu.dnetlib.lbs.controllers.objects.BufferStatus;
import eu.dnetlib.lbs.controllers.objects.CurrentStatus;
import eu.dnetlib.lbs.controllers.objects.DispatcherStatus;
import eu.dnetlib.lbs.controllers.objects.ThreadStatus;
import eu.dnetlib.lbs.controllers.objects.Tool;
import eu.dnetlib.lbs.elasticsearch.EventRepository;
import eu.dnetlib.lbs.elasticsearch.NotificationRepository;
import eu.dnetlib.lbs.events.output.DispatcherManager;
import eu.dnetlib.lbs.events.output.NotificationDispatcher;
import eu.dnetlib.lbs.subscriptions.SubscriptionRepository;
import eu.dnetlib.lbs.topics.TopicTypeRepository;
import eu.dnetlib.lbs.utils.LbsQueue;
import eu.dnetlib.lbs.utils.QueueManager;
import eu.dnetlib.lbs.utils.ThreadManager;

@RestController
@RequestMapping("/ajax")
public class AjaxController extends AbstractLbsController {

	@Autowired
	private EventRepository eventRepository;

	@Autowired
	private NotificationRepository notificationRepository;

	@Autowired
	private QueueManager queueManager;

	@Autowired
	private SubscriptionRepository subscriptionRepo;

	@Autowired
	private TopicTypeRepository topicTypeRepo;

	@Autowired
	private DispatcherManager dispatcherManager;

	@Autowired
	private CurrentStatus currentStatus;

	@Autowired
	private ThreadManager threadManager;

	@Value("${lbs.rabbit.homepage}")
	private String rabbitmqUiUrl;

	@Value("${lbs.elastic.homepage}")
	private String elasticSearchUiUrl;

	@Value("${lbs.rabbit.enabled}")
	private boolean rabbitmqEnabled;

	@RequestMapping(value = "externalTools", method = RequestMethod.GET)
	public List<Tool> listExternalUrls() {
		final List<Tool> tools = new ArrayList<>();

		tools.add(new Tool("ElasticSearch", this.elasticSearchUiUrl));

		if (this.rabbitmqEnabled) {
			tools.add(new Tool("RabbitMQ", this.rabbitmqUiUrl));
		}

		return tools;
	}

	@RequestMapping(value = "summary", method = RequestMethod.GET)
	public CurrentStatus eventSummary() {

		final List<BufferStatus> buffers = this.queueManager.getLbsQueues()
				.stream()
				.map(q -> new BufferStatus(q.getName(), q.size(), q.getLostRecords(), q.getSkippedRecords(), q.getInvalidRecords()))
				.sorted()
				.collect(Collectors.toList());

		final List<DispatcherStatus> dispatchers = this.dispatcherManager.getDispatchers()
				.stream()
				.map(d -> new DispatcherStatus(d.getDispatcherName(), d.count()))
				.sorted()
				.collect(Collectors.toList());

		final List<ThreadStatus> threads = this.threadManager.getThreads()
				.stream()
				.map(t -> new ThreadStatus(t.getName(), t.getState().toString(), t.isAlive()))
				.sorted()
				.collect(Collectors.toList());

		synchronized (this.currentStatus) {
			this.currentStatus.setBuffers(buffers);
			this.currentStatus.setDispatchers(dispatchers);
			this.currentStatus.setThreads(threads);
			this.currentStatus.getTotals().put("topics", this.topicTypeRepo.count());
			this.currentStatus.getTotals().put("events", this.eventRepository.count());
			this.currentStatus.getTotals().put("subscriptions", this.subscriptionRepo.count());
			this.currentStatus.getTotals().put("notifications", this.notificationRepository.count());

			return this.currentStatus;
		}
	}

	@RequestMapping(value = "/resetCounters", method = RequestMethod.GET)
	public CurrentStatus resetCounters() {
		this.dispatcherManager.getDispatchers().forEach(NotificationDispatcher::resetCount);
		this.queueManager.getLbsQueues().forEach(LbsQueue::resetCounters);
		return eventSummary();
	}

}
