package eu.dnetlib.broker.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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import eu.dnetlib.broker.common.elasticsearch.EventRepository;
import eu.dnetlib.broker.common.elasticsearch.NotificationRepository;
import eu.dnetlib.broker.common.stats.OpenaireDsStatRepository;
import eu.dnetlib.broker.common.subscriptions.SubscriptionRepository;
import eu.dnetlib.broker.common.topics.TopicTypeRepository;
import eu.dnetlib.broker.controllers.objects.BufferStatus;
import eu.dnetlib.broker.controllers.objects.CurrentStatus;
import eu.dnetlib.broker.controllers.objects.DispatcherStatus;
import eu.dnetlib.broker.controllers.objects.ThreadStatus;
import eu.dnetlib.broker.controllers.objects.Tool;
import eu.dnetlib.broker.events.output.DispatcherManager;
import eu.dnetlib.broker.events.output.NotificationDispatcher;
import eu.dnetlib.broker.utils.LbsQueue;
import eu.dnetlib.broker.utils.QueueManager;
import eu.dnetlib.broker.utils.ThreadManager;
import eu.dnetlib.common.controller.AbstractDnetController;

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

	@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;

	@Autowired
	private OpenaireDsStatRepository openaireDsStatRepository;

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

	@GetMapping("externalTools")
	public List<Tool> listExternalUrls() {
		final List<Tool> tools = new ArrayList<>();

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

		return tools;
	}

	@GetMapping("summary")
	public CurrentStatus eventSummary() {

		final List<BufferStatus> buffers = 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 = dispatcherManager.getDispatchers()
			.stream()
			.map(d -> new DispatcherStatus(d.getDispatcherName(), d.count(), d.countErrors(), d.lastError()))
			.sorted()
			.collect(Collectors.toList());

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

		synchronized (currentStatus) {
			currentStatus.setBuffers(buffers);
			currentStatus.setDispatchers(dispatchers);
			currentStatus.setThreads(threads);
			currentStatus.getTotals().put("topics", topicTypeRepo.count());
			currentStatus.getTotals().put("events_es", eventRepository.count());
			currentStatus.getTotals().put("events_db", openaireDsStatRepository.totalEvents());
			currentStatus.getTotals().put("subscriptions", subscriptionRepo.count());
			currentStatus.getTotals().put("notifications_es", notificationRepository.count());

			return currentStatus;
		}
	}

	@GetMapping("/resetCounters")
	public CurrentStatus resetCounters() {
		dispatcherManager.getDispatchers().forEach(NotificationDispatcher::resetCount);
		queueManager.getLbsQueues().forEach(LbsQueue::resetCounters);
		return eventSummary();
	}

}
