package cz.senslog.analytics.module;

import cz.senslog.analytics.domain.MessageBrokerConfig;
import cz.senslog.analytics.domain.SourceToMessageBroker;
import cz.senslog.analytics.domain.ThresholdViolationNotification;
import cz.senslog.analytics.module.api.SimpleModule;
import cz.senslog.analytics.messaging.MessageBroker;
import cz.senslog.analytics.repository.ConfigurationRepository;
import io.vertx.core.json.JsonObject;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


public final class NotificationModule extends SimpleModule {

    private static final Logger logger = LogManager.getLogger(NotificationModule.class);

    private record SourceSender(MessageBroker messageBroker, JsonObject properties) {
        public void send(ThresholdViolationNotification notification) {
            messageBroker.send(notification, properties);
        }
    }

    private static final SourceSender DEFAULT_SOURCE_SENDER = new SourceSender((n, props) ->
            logger.warn("No notification sender for source {}.", n.groupId()), null);

    private final ConfigurationRepository repo;

    private Map<Long, SourceSender> senders;

    public NotificationModule(ConfigurationRepository repo) {
        this.repo = repo;
        this.senders = Collections.emptyMap();
    }

    @Override
    public void configure() {
        repo.loadMessageBrokers().onSuccess(brokers -> {
            Map<Long, MessageBroker> msgBrokerMap = new HashMap<>(brokers.size());
            for (MessageBrokerConfig brokerConfig : brokers) {
                msgBrokerMap.put(brokerConfig.id(), brokerConfig.senderType().createBroker(brokerConfig.config()));
            }
            repo.loadSourceToMessageBrokerMapping().onSuccess(mapping -> {
                senders = new HashMap<>(mapping.size());
                for (SourceToMessageBroker sToMsgConfig : mapping) {
                    MessageBroker msgBroker = msgBrokerMap.getOrDefault(sToMsgConfig.messageBrokerId(), DEFAULT_SOURCE_SENDER.messageBroker);
                    senders.put(sToMsgConfig.thresholdId(), new SourceSender(msgBroker, sToMsgConfig.properties()));
                }
            }).onFailure(logger::catching);
        }).onFailure(logger::catching);
    }

    @Override
    public void run() {
        vertx.eventBus().<ThresholdViolationNotification>consumer(id(),
                msg -> senders.getOrDefault(msg.body().groupId(), DEFAULT_SOURCE_SENDER).send(msg.body()));
    }
}