package dev.lions.unionflow.server.service;

import static org.mockito.Mockito.*;

import io.quarkus.websockets.next.OpenConnections;
import io.quarkus.websockets.next.WebSocketConnection;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import org.junit.jupiter.api.BeforeEach;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

class WebSocketBroadcastServiceTest {

    WebSocketBroadcastService broadcastService;

    @Mock
    OpenConnections openConnections;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
        broadcastService = new WebSocketBroadcastService();
        broadcastService.openConnections = openConnections;
    }

    @Test
    @DisplayName("broadcast envoie un message à toutes les connexions")
    void broadcast_sendsToAll() {
        WebSocketConnection conn1 = mock(WebSocketConnection.class);
        WebSocketConnection conn2 = mock(WebSocketConnection.class);

        when(openConnections.stream()).thenReturn(Stream.of(conn1, conn2));
        doAnswer(invocation -> {
            java.util.function.Consumer<WebSocketConnection> consumer = invocation.getArgument(0);
            consumer.accept(conn1);
            consumer.accept(conn2);
            return null;
        }).when(openConnections).forEach(any());

        broadcastService.broadcast("Hello");

        verify(conn1).sendTextAndAwait("Hello");
        verify(conn2).sendTextAndAwait("Hello");
    }

    @Test
    @DisplayName("broadcastStatsUpdate formate correctement le message")
    void broadcastStatsUpdate_formatsMessage() {
        WebSocketConnection conn = mock(WebSocketConnection.class);
        when(openConnections.stream()).thenReturn(Stream.of(conn));
        doAnswer(invocation -> {
            java.util.function.Consumer<WebSocketConnection> consumer = invocation.getArgument(0);
            consumer.accept(conn);
            return null;
        }).when(openConnections).forEach(any());

        broadcastService.broadcastStatsUpdate("{\"active\":10}");

        verify(conn).sendTextAndAwait("{\"type\":\"stats_update\",\"data\":{\"active\":10}}");
    }

    @Test
    @DisplayName("broadcastNewActivity formate correctement le message")
    void broadcastNewActivity_formatsMessage() {
        WebSocketConnection conn = mock(WebSocketConnection.class);
        when(openConnections.stream()).thenReturn(Stream.of(conn));
        doAnswer(invocation -> {
            java.util.function.Consumer<WebSocketConnection> consumer = invocation.getArgument(0);
            consumer.accept(conn);
            return null;
        }).when(openConnections).forEach(any());

        broadcastService.broadcastNewActivity("{\"action\":\"join\"}");

        verify(conn).sendTextAndAwait("{\"type\":\"new_activity\",\"data\":{\"action\":\"join\"}}");
    }

    @Test
    @DisplayName("broadcastEventUpdate formate correctement le message")
    void broadcastEventUpdate_formatsMessage() {
        WebSocketConnection conn = mock(WebSocketConnection.class);
        when(openConnections.stream()).thenReturn(Stream.of(conn));
        doAnswer(invocation -> {
            java.util.function.Consumer<WebSocketConnection> consumer = invocation.getArgument(0);
            consumer.accept(conn);
            return null;
        }).when(openConnections).forEach(any());

        broadcastService.broadcastEventUpdate("{\"eventId\":\"1\"}");

        verify(conn).sendTextAndAwait("{\"type\":\"event_update\",\"data\":{\"eventId\":\"1\"}}");
    }

    @Test
    @DisplayName("broadcastNotification formate correctement le message")
    void broadcastNotification_formatsMessage() {
        WebSocketConnection conn = mock(WebSocketConnection.class);
        when(openConnections.stream()).thenReturn(Stream.of(conn));
        doAnswer(invocation -> {
            java.util.function.Consumer<WebSocketConnection> consumer = invocation.getArgument(0);
            consumer.accept(conn);
            return null;
        }).when(openConnections).forEach(any());

        broadcastService.broadcastNotification("{\"msg\":\"hello\"}");

        verify(conn).sendTextAndAwait("{\"type\":\"notification\",\"data\":{\"msg\":\"hello\"}}");
    }
}
