package dev.lions.unionflow.server.messaging;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;

import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Tests d'intégration pour KafkaEventProducer.
 *
 * <p>Utilise le connecteur in-memory SmallRye (configuré dans application-test.properties)
 * pour éviter toute dépendance à un broker Kafka réel.
 * Vérifie que chaque méthode de publication ne lève pas d'exception.
 *
 * @author UnionFlow Team
 */
@QuarkusTest
@DisplayName("KafkaEventProducer")
class KafkaEventProducerTest {

    @Inject
    KafkaEventProducer kafkaEventProducer;

    private static final UUID APPROVAL_ID = UUID.randomUUID();
    private static final UUID MEMBER_ID = UUID.randomUUID();
    private static final UUID CONTRIBUTION_ID = UUID.randomUUID();
    private static final String ORG_ID = UUID.randomUUID().toString();
    private static final String USER_ID = UUID.randomUUID().toString();

    private Map<String, Object> sampleData() {
        Map<String, Object> data = new HashMap<>();
        data.put("montant", 150000);
        data.put("devise", "XOF");
        data.put("statut", "EN_ATTENTE");
        return data;
    }

    // =========================================================================
    // Injection
    // =========================================================================

    @Test
    @DisplayName("KafkaEventProducer est injectable et non null")
    void producerIsInjected() {
        assertThat(kafkaEventProducer).isNotNull();
    }

    // =========================================================================
    // Finance approvals
    // =========================================================================

    @Test
    @DisplayName("publishApprovalPending - ne leve pas d'exception")
    void publishApprovalPending_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishApprovalPending(APPROVAL_ID, ORG_ID, sampleData())
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishApprovalPending - data null - ne leve pas d'exception")
    void publishApprovalPending_dataNul_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishApprovalPending(APPROVAL_ID, ORG_ID, null)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishApprovalApproved - ne leve pas d'exception")
    void publishApprovalApproved_sansException() {
        Map<String, Object> data = sampleData();
        data.put("approbateur", "admin@test.com");

        assertThatCode(() ->
                kafkaEventProducer.publishApprovalApproved(APPROVAL_ID, ORG_ID, data)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishApprovalRejected - ne leve pas d'exception")
    void publishApprovalRejected_sansException() {
        Map<String, Object> data = sampleData();
        data.put("motif", "Documents manquants");

        assertThatCode(() ->
                kafkaEventProducer.publishApprovalRejected(APPROVAL_ID, ORG_ID, data)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishApprovalRejected - organizationId null - ne leve pas d'exception")
    void publishApprovalRejected_organizationIdNull_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishApprovalRejected(APPROVAL_ID, null, sampleData())
        ).doesNotThrowAnyException();
    }

    // =========================================================================
    // Dashboard stats
    // =========================================================================

    @Test
    @DisplayName("publishDashboardStatsUpdate - ne leve pas d'exception")
    void publishDashboardStatsUpdate_sansException() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalMembres", 250);
        stats.put("totalCotisations", 12500000);
        stats.put("tauxRecouvrement", 0.85);

        assertThatCode(() ->
                kafkaEventProducer.publishDashboardStatsUpdate(ORG_ID, stats)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishKpiUpdate - ne leve pas d'exception")
    void publishKpiUpdate_sansException() {
        Map<String, Object> kpiData = new HashMap<>();
        kpiData.put("kpi", "TAUX_ADHESION");
        kpiData.put("valeur", 0.92);

        assertThatCode(() ->
                kafkaEventProducer.publishKpiUpdate(ORG_ID, kpiData)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishKpiUpdate - data vide - ne leve pas d'exception")
    void publishKpiUpdate_dataVide_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishKpiUpdate(ORG_ID, new HashMap<>())
        ).doesNotThrowAnyException();
    }

    // =========================================================================
    // Notifications
    // =========================================================================

    @Test
    @DisplayName("publishUserNotification - ne leve pas d'exception")
    void publishUserNotification_sansException() {
        Map<String, Object> notif = new HashMap<>();
        notif.put("titre", "Paiement recu");
        notif.put("message", "Votre cotisation de 5000 XOF a ete enregistree.");
        notif.put("type", "COTISATION");

        assertThatCode(() ->
                kafkaEventProducer.publishUserNotification(USER_ID, notif)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishUserNotification - payload minimal - ne leve pas d'exception")
    void publishUserNotification_payloadMinimal_sansException() {
        Map<String, Object> notif = new HashMap<>();
        notif.put("message", "Test");

        assertThatCode(() ->
                kafkaEventProducer.publishUserNotification(USER_ID, notif)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishBroadcastNotification - ne leve pas d'exception")
    void publishBroadcastNotification_sansException() {
        Map<String, Object> notif = new HashMap<>();
        notif.put("titre", "Reunion annuelle");
        notif.put("message", "La reunion annuelle est prevue le 15 mars 2026");
        notif.put("type", "EVENEMENT");

        assertThatCode(() ->
                kafkaEventProducer.publishBroadcastNotification(ORG_ID, notif)
        ).doesNotThrowAnyException();
    }

    // =========================================================================
    // Members events
    // =========================================================================

    @Test
    @DisplayName("publishMemberCreated - ne leve pas d'exception")
    void publishMemberCreated_sansException() {
        Map<String, Object> memberData = new HashMap<>();
        memberData.put("nom", "Diallo");
        memberData.put("prenom", "Amadou");
        memberData.put("email", "amadou.diallo@test.com");

        assertThatCode(() ->
                kafkaEventProducer.publishMemberCreated(MEMBER_ID, ORG_ID, memberData)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishMemberUpdated - ne leve pas d'exception")
    void publishMemberUpdated_sansException() {
        Map<String, Object> memberData = new HashMap<>();
        memberData.put("telephone", "+2250700000001");

        assertThatCode(() ->
                kafkaEventProducer.publishMemberUpdated(MEMBER_ID, ORG_ID, memberData)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishMemberUpdated - organizationId null - ne leve pas d'exception")
    void publishMemberUpdated_organizationIdNull_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishMemberUpdated(MEMBER_ID, null, sampleData())
        ).doesNotThrowAnyException();
    }

    // =========================================================================
    // Contributions events
    // =========================================================================

    @Test
    @DisplayName("publishContributionPaid - ne leve pas d'exception")
    void publishContributionPaid_sansException() {
        Map<String, Object> contributionData = new HashMap<>();
        contributionData.put("montant", 5000);
        contributionData.put("devise", "XOF");
        contributionData.put("periode", "2026-03");

        assertThatCode(() ->
                kafkaEventProducer.publishContributionPaid(CONTRIBUTION_ID, ORG_ID, contributionData)
        ).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("publishContributionPaid - data null - ne leve pas d'exception")
    void publishContributionPaid_dataNul_sansException() {
        assertThatCode(() ->
                kafkaEventProducer.publishContributionPaid(CONTRIBUTION_ID, ORG_ID, null)
        ).doesNotThrowAnyException();
    }
}
