package de.assecutor.votianlt.service;

import com.vaadin.flow.shared.Registration;
import de.assecutor.votianlt.event.MessageReceivedEvent;
import de.assecutor.votianlt.model.Message;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.LinkedHashSet;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

/**
 * Broadcaster service that manages listeners for incoming messages and notifies
 * UI components in a thread-safe manner
 */
@Service
@Slf4j
public class MessageBroadcaster {

    private final Executor executor = Executors.newSingleThreadExecutor();
    private final LinkedHashSet<Consumer<Message>> listeners = new LinkedHashSet<>();

    /**
     * Register a listener for incoming messages
     * 
     * @param listener
     *            Consumer that will be called when a new message arrives
     * @return Registration object that can be used to unregister the listener
     */
    public synchronized Registration register(Consumer<Message> listener) {
        listeners.add(listener);
        log.debug("Registered message listener. Total listeners: {}", listeners.size());

        return () -> {
            synchronized (MessageBroadcaster.this) {
                listeners.remove(listener);
                log.debug("Unregistered message listener. Total listeners: {}", listeners.size());
            }
        };
    }

    /**
     * Broadcast a message to all registered listeners This is called asynchronously
     * to avoid blocking the message reception
     */
    private synchronized void broadcast(Message message) {
        log.debug("Broadcasting message to {} listeners", listeners.size());
        for (Consumer<Message> listener : listeners) {
            executor.execute(() -> {
                try {
                    listener.accept(message);
                } catch (Exception e) {
                    log.error("Error broadcasting message to listener", e);
                }
            });
        }
    }

    /**
     * Spring event listener that gets called when a MessageReceivedEvent is
     * published
     */
    @EventListener
    public void onMessageReceived(MessageReceivedEvent event) {
        Message message = event.getMessage();
        log.info("MessageBroadcaster received event for message with origin {} for receiver {}", message.getOrigin(),
                message.getReceiver());
        broadcast(message);
    }
}
