package dev.lions.unionflow.server.service;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

import dev.lions.unionflow.server.api.dto.wave.CompteWaveDTO;
import dev.lions.unionflow.server.api.dto.wave.TransactionWaveDTO;
import dev.lions.unionflow.server.api.enums.wave.StatutCompteWave;
import dev.lions.unionflow.server.api.enums.wave.StatutTransactionWave;
import dev.lions.unionflow.server.api.enums.wave.TypeTransactionWave;
import dev.lions.unionflow.server.entity.CompteWave;
import dev.lions.unionflow.server.entity.Membre;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.TransactionWave;
import dev.lions.unionflow.server.repository.CompteWaveRepository;
import dev.lions.unionflow.server.repository.MembreRepository;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.TransactionWaveRepository;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@QuarkusTest
class WaveServiceTest {

    @Inject
    WaveService waveService;

    @InjectMock
    CompteWaveRepository compteWaveRepository;

    @InjectMock
    TransactionWaveRepository transactionWaveRepository;

    @InjectMock
    OrganisationRepository organisationRepository;

    @InjectMock
    MembreRepository membreRepository;

    @InjectMock
    KeycloakService keycloakService;

    @InjectMock
    DefaultsService defaultsService;

    @Test
    @DisplayName("creerCompteWave persiste un nouveau compte")
    void creerCompteWave_persistsAccount() {
        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("771234567");
        dto.setStatutCompte(StatutCompteWave.NON_VERIFIE);

        when(compteWaveRepository.findByNumeroTelephone("771234567")).thenReturn(Optional.empty());
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@unionflow.dev");

        CompteWaveDTO created = waveService.creerCompteWave(dto);

        assertThat(created).isNotNull();
        assertThat(created.getNumeroTelephone()).isEqualTo("771234567");
        verify(compteWaveRepository).persist(any(CompteWave.class));
    }

    @Test
    @DisplayName("creerCompteWave avec numéro existant lance IllegalArgumentException")
    void creerCompteWave_duplicatePhone_throws() {
        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("771234567");

        CompteWave existing = new CompteWave();
        existing.setNumeroTelephone("771234567");
        when(compteWaveRepository.findByNumeroTelephone("771234567")).thenReturn(Optional.of(existing));

        assertThatThrownBy(() -> waveService.creerCompteWave(dto))
                .isInstanceOf(IllegalArgumentException.class)
                .hasMessageContaining("Un compte Wave existe déjà");
    }

    @Test
    @DisplayName("mettreAJourCompteWave met à jour les champs du compte")
    void mettreAJourCompteWave_updatesFields() {
        UUID id = UUID.randomUUID();
        CompteWave existingCompte = new CompteWave();
        existingCompte.setId(id);
        existingCompte.setStatutCompte(StatutCompteWave.NON_VERIFIE);

        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.of(existingCompte));
        when(keycloakService.getCurrentUserEmail()).thenReturn("updater@test.com");

        CompteWaveDTO updateDto = new CompteWaveDTO();
        updateDto.setStatutCompte(StatutCompteWave.VERIFIE);
        updateDto.setWaveAccountId("WAVE123");
        updateDto.setCommentaire("Compte validé");

        CompteWaveDTO updated = waveService.mettreAJourCompteWave(id, updateDto);

        assertThat(existingCompte.getStatutCompte()).isEqualTo(StatutCompteWave.VERIFIE);
        assertThat(existingCompte.getWaveAccountId()).isEqualTo("WAVE123");
        assertThat(existingCompte.getCommentaire()).isEqualTo("Compte validé");
        verify(compteWaveRepository).persist(existingCompte);
    }

    @Test
    @DisplayName("mettreAJourCompteWave avec ID inexistant lance NotFoundException")
    void mettreAJourCompteWave_notFound_throws() {
        UUID id = UUID.randomUUID();
        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.empty());

        CompteWaveDTO updateDto = new CompteWaveDTO();

        assertThatThrownBy(() -> waveService.mettreAJourCompteWave(id, updateDto))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining("Compte Wave non trouvé");
    }

    @Test
    @DisplayName("verifierCompteWave passe le statut à VERIFIE")
    void verifierCompteWave_updatesStatus() {
        UUID id = UUID.randomUUID();
        CompteWave compte = new CompteWave();
        compte.setId(id);
        compte.setStatutCompte(StatutCompteWave.NON_VERIFIE);

        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.of(compte));

        waveService.verifierCompteWave(id);

        assertThat(compte.getStatutCompte()).isEqualTo(StatutCompteWave.VERIFIE);
        assertThat(compte.getDateDerniereVerification()).isNotNull();
    }

    @Test
    @DisplayName("verifierCompteWave avec ID inexistant lance NotFoundException")
    void verifierCompteWave_notFound_throws() {
        UUID id = UUID.randomUUID();
        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.verifierCompteWave(id))
                .isInstanceOf(NotFoundException.class);
    }

    @Test
    @DisplayName("trouverCompteWaveParId retourne le compte")
    void trouverCompteWaveParId_found_returnsCompte() {
        UUID id = UUID.randomUUID();
        CompteWave compte = new CompteWave();
        compte.setId(id);
        compte.setNumeroTelephone("771234567");

        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.of(compte));

        CompteWaveDTO result = waveService.trouverCompteWaveParId(id);

        assertThat(result).isNotNull();
        assertThat(result.getId()).isEqualTo(id);
        assertThat(result.getNumeroTelephone()).isEqualTo("771234567");
    }

    @Test
    @DisplayName("trouverCompteWaveParId avec ID inexistant lance NotFoundException")
    void trouverCompteWaveParId_notFound_throws() {
        UUID id = UUID.randomUUID();
        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.trouverCompteWaveParId(id))
                .isInstanceOf(NotFoundException.class);
    }

    @Test
    @DisplayName("trouverCompteWaveParTelephone retourne le compte si trouvé")
    void trouverCompteWaveParTelephone_found_returnsCompte() {
        CompteWave compte = new CompteWave();
        compte.setNumeroTelephone("771111111");

        when(compteWaveRepository.findByNumeroTelephone("771111111")).thenReturn(Optional.of(compte));

        CompteWaveDTO result = waveService.trouverCompteWaveParTelephone("771111111");

        assertThat(result).isNotNull();
        assertThat(result.getNumeroTelephone()).isEqualTo("771111111");
    }

    @Test
    @DisplayName("trouverCompteWaveParTelephone retourne null si non trouvé")
    void trouverCompteWaveParTelephone_notFound_returnsNull() {
        when(compteWaveRepository.findByNumeroTelephone("999999999")).thenReturn(Optional.empty());

        CompteWaveDTO result = waveService.trouverCompteWaveParTelephone("999999999");

        assertThat(result).isNull();
    }

    @Test
    @DisplayName("listerComptesWaveParOrganisation retourne tous les comptes")
    void listerComptesWaveParOrganisation_returnsAllComptes() {
        UUID orgId = UUID.randomUUID();
        CompteWave compte1 = new CompteWave();
        compte1.setNumeroTelephone("771111111");
        CompteWave compte2 = new CompteWave();
        compte2.setNumeroTelephone("772222222");

        when(compteWaveRepository.findByOrganisationId(orgId)).thenReturn(Arrays.asList(compte1, compte2));

        List<CompteWaveDTO> result = waveService.listerComptesWaveParOrganisation(orgId);

        assertThat(result).hasSize(2);
        assertThat(result).extracting(CompteWaveDTO::getNumeroTelephone)
                .containsExactlyInAnyOrder("771111111", "772222222");
    }

    @Test
    @DisplayName("creerTransactionWave persiste une nouvelle transaction")
    void creerTransactionWave_persistsTransaction() {
        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-TX-123");
        dto.setTypeTransaction(TypeTransactionWave.PAIEMENT);
        dto.setMontant(new BigDecimal("10000"));
        dto.setTelephonePayeur("771234567");

        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");
        when(defaultsService.getDevise()).thenReturn("XOF");

        TransactionWaveDTO created = waveService.creerTransactionWave(dto);

        assertThat(created).isNotNull();
        verify(transactionWaveRepository).persist(any(TransactionWave.class));
    }

    @Test
    @DisplayName("mettreAJourStatutTransaction met à jour le statut")
    void mettreAJourStatutTransaction_updatesStatus() {
        String waveId = "WAVE-TX-456";
        TransactionWave transaction = new TransactionWave();
        transaction.setWaveTransactionId(waveId);
        transaction.setStatutTransaction(StatutTransactionWave.INITIALISE);

        when(transactionWaveRepository.findByWaveTransactionId(waveId)).thenReturn(Optional.of(transaction));
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");

        TransactionWaveDTO updated = waveService.mettreAJourStatutTransaction(waveId, StatutTransactionWave.REUSSIE);

        assertThat(transaction.getStatutTransaction()).isEqualTo(StatutTransactionWave.REUSSIE);
        assertThat(transaction.getDateDerniereTentative()).isNotNull();
        verify(transactionWaveRepository).persist(transaction);
    }

    @Test
    @DisplayName("mettreAJourStatutTransaction avec ID inexistant lance NotFoundException")
    void mettreAJourStatutTransaction_notFound_throws() {
        String waveId = "WAVE-INVALID";
        when(transactionWaveRepository.findByWaveTransactionId(waveId)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.mettreAJourStatutTransaction(waveId, StatutTransactionWave.REUSSIE))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining("Transaction Wave non trouvée");
    }

    @Test
    @DisplayName("trouverTransactionWaveParId retourne la transaction")
    void trouverTransactionWaveParId_found_returnsTransaction() {
        String waveId = "WAVE-TX-789";
        TransactionWave transaction = new TransactionWave();
        transaction.setWaveTransactionId(waveId);
        transaction.setMontant(new BigDecimal("5000"));

        when(transactionWaveRepository.findByWaveTransactionId(waveId)).thenReturn(Optional.of(transaction));

        TransactionWaveDTO result = waveService.trouverTransactionWaveParId(waveId);

        assertThat(result).isNotNull();
        assertThat(result.getWaveTransactionId()).isEqualTo(waveId);
        assertThat(result.getMontant()).isEqualByComparingTo("5000");
    }

    @Test
    @DisplayName("trouverTransactionWaveParId avec ID inexistant lance NotFoundException")
    void trouverTransactionWaveParId_notFound_throws() {
        String waveId = "WAVE-MISSING";
        when(transactionWaveRepository.findByWaveTransactionId(waveId)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.trouverTransactionWaveParId(waveId))
                .isInstanceOf(NotFoundException.class);
    }

    // =========================================================================
    // convertToDTO(CompteWave) — branches avec organisation et membre non null
    // Couvertes via creerCompteWave/trouverCompteWaveParId
    // =========================================================================

    @Test
    @DisplayName("convertToDTO CompteWave avec organisation et membre — organisationId et membreId mappés")
    void convertToDTO_compteWave_avecOrganisationEtMembre_idsMappees() {
        UUID id = UUID.randomUUID();
        UUID orgId = UUID.randomUUID();
        UUID membreId = UUID.randomUUID();

        Organisation org = new Organisation();
        org.setId(orgId);

        Membre membre = new Membre();
        membre.setId(membreId);

        CompteWave compte = new CompteWave();
        compte.setId(id);
        compte.setNumeroTelephone("771234567");
        compte.setStatutCompte(StatutCompteWave.VERIFIE);
        compte.setOrganisation(org);
        compte.setMembre(membre);

        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.of(compte));

        CompteWaveDTO result = waveService.trouverCompteWaveParId(id);

        assertThat(result).isNotNull();
        assertThat(result.getOrganisationId()).isEqualTo(orgId);
        assertThat(result.getMembreId()).isEqualTo(membreId);
    }

    @Test
    @DisplayName("creerCompteWave avec organisationId — organisation liée via repository")
    void creerCompteWave_avecOrganisationId_organisationLiee() {
        UUID orgId = UUID.randomUUID();

        Organisation org = new Organisation();
        org.setId(orgId);

        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("779876543");
        dto.setOrganisationId(orgId);

        when(compteWaveRepository.findByNumeroTelephone("779876543")).thenReturn(Optional.empty());
        when(organisationRepository.findByIdOptional(orgId)).thenReturn(Optional.of(org));
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");

        CompteWaveDTO result = waveService.creerCompteWave(dto);

        assertThat(result).isNotNull();
        assertThat(result.getNumeroTelephone()).isEqualTo("779876543");
        verify(compteWaveRepository).persist(any(CompteWave.class));
    }

    @Test
    @DisplayName("creerCompteWave avec organisationId inexistant lance NotFoundException")
    void creerCompteWave_avecOrganisationIdInexistant_lancerNotFoundException() {
        UUID orgId = UUID.randomUUID();

        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("778888888");
        dto.setOrganisationId(orgId);

        when(compteWaveRepository.findByNumeroTelephone("778888888")).thenReturn(Optional.empty());
        when(organisationRepository.findByIdOptional(orgId)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.creerCompteWave(dto))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining("Organisation non trouvée");
    }

    @Test
    @DisplayName("creerCompteWave avec membreId — membre lié via repository")
    void creerCompteWave_avecMembreId_membreLie() {
        UUID membreId = UUID.randomUUID();

        Membre membre = new Membre();
        membre.setId(membreId);

        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("775555555");
        dto.setMembreId(membreId);

        when(compteWaveRepository.findByNumeroTelephone("775555555")).thenReturn(Optional.empty());
        when(membreRepository.findByIdOptional(membreId)).thenReturn(Optional.of(membre));
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");

        CompteWaveDTO result = waveService.creerCompteWave(dto);

        assertThat(result).isNotNull();
        verify(compteWaveRepository).persist(any(CompteWave.class));
    }

    @Test
    @DisplayName("creerCompteWave avec membreId inexistant lance NotFoundException")
    void creerCompteWave_avecMembreIdInexistant_lancerNotFoundException() {
        UUID membreId = UUID.randomUUID();

        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("774444444");
        dto.setMembreId(membreId);

        when(compteWaveRepository.findByNumeroTelephone("774444444")).thenReturn(Optional.empty());
        when(membreRepository.findByIdOptional(membreId)).thenReturn(Optional.empty());

        assertThatThrownBy(() -> waveService.creerCompteWave(dto))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining("Membre non trouvé");
    }

    @Test
    @DisplayName("creerTransactionWave avec compteWaveId — compteWave lié via repository")
    void creerTransactionWave_avecCompteWaveId_compteWaveLie() {
        UUID compteWaveId = UUID.randomUUID();

        CompteWave compteWave = new CompteWave();
        compteWave.setId(compteWaveId);
        compteWave.setNumeroTelephone("771111111");

        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-TX-WITH-COMPTE");
        dto.setTypeTransaction(TypeTransactionWave.PAIEMENT);
        dto.setMontant(new BigDecimal("5000"));
        dto.setCompteWaveId(compteWaveId);

        when(compteWaveRepository.findCompteWaveById(compteWaveId)).thenReturn(Optional.of(compteWave));
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");
        when(defaultsService.getDevise()).thenReturn("XOF");

        TransactionWaveDTO result = waveService.creerTransactionWave(dto);

        assertThat(result).isNotNull();
        verify(transactionWaveRepository).persist(any(TransactionWave.class));
    }

    @Test
    @DisplayName("creerTransactionWave avec compteWaveId inexistant lance NotFoundException")
    void creerTransactionWave_avecCompteWaveIdInexistant_lancerNotFoundException() {
        UUID compteWaveId = UUID.randomUUID();

        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-TX-INVALID-COMPTE");
        dto.setCompteWaveId(compteWaveId);

        when(compteWaveRepository.findCompteWaveById(compteWaveId)).thenReturn(Optional.empty());
        when(defaultsService.getDevise()).thenReturn("XOF");

        assertThatThrownBy(() -> waveService.creerTransactionWave(dto))
                .isInstanceOf(NotFoundException.class)
                .hasMessageContaining("Compte Wave non trouvé");
    }

    @Test
    @DisplayName("convertToDTO TransactionWave avec compteWave non null — compteWaveId mappé")
    void convertToDTO_transactionWave_avecCompteWave_compteWaveIdMappee() {
        UUID compteWaveId = UUID.randomUUID();
        String waveId = "WAVE-TX-MAPPING";

        CompteWave compteWave = new CompteWave();
        compteWave.setId(compteWaveId);

        TransactionWave transaction = new TransactionWave();
        transaction.setWaveTransactionId(waveId);
        transaction.setMontant(new BigDecimal("7500"));
        transaction.setCompteWave(compteWave);

        when(transactionWaveRepository.findByWaveTransactionId(waveId)).thenReturn(Optional.of(transaction));

        TransactionWaveDTO result = waveService.trouverTransactionWaveParId(waveId);

        assertThat(result).isNotNull();
        assertThat(result.getCompteWaveId()).isEqualTo(compteWaveId);
    }

    @Test
    @DisplayName("updateFromDTO — environnement et dateDerniereVerification mis à jour si non null")
    void updateFromDTO_environnementEtDate_miseAJour() {
        UUID id = UUID.randomUUID();
        CompteWave existingCompte = new CompteWave();
        existingCompte.setId(id);
        existingCompte.setStatutCompte(StatutCompteWave.NON_VERIFIE);
        existingCompte.setEnvironnement("SANDBOX");

        when(compteWaveRepository.findCompteWaveById(id)).thenReturn(Optional.of(existingCompte));
        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");

        LocalDateTime verificationDate = LocalDateTime.now().minusDays(1);
        CompteWaveDTO updateDto = new CompteWaveDTO();
        updateDto.setEnvironnement("PRODUCTION");
        updateDto.setDateDerniereVerification(verificationDate);

        waveService.mettreAJourCompteWave(id, updateDto);

        assertThat(existingCompte.getEnvironnement()).isEqualTo("PRODUCTION");
        assertThat(existingCompte.getDateDerniereVerification()).isEqualTo(verificationDate);
    }

    @Test
    @DisplayName("creerTransactionWave avec statut null — statut défaut INITIALISE")
    void creerTransactionWave_statutNull_statutDefautInitialise() {
        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-TX-NO-STATUT");
        dto.setStatutTransaction(null); // null → INITIALISE
        dto.setMontant(new BigDecimal("2000"));

        when(keycloakService.getCurrentUserEmail()).thenReturn("admin@test.com");
        when(defaultsService.getDevise()).thenReturn("XOF");

        TransactionWaveDTO result = waveService.creerTransactionWave(dto);

        assertThat(result).isNotNull();
        verify(transactionWaveRepository).persist(any(TransactionWave.class));
    }

    // =========================================================================
    // Branches null des méthodes privées (via réflexion)
    // =========================================================================

    @Test
    @DisplayName("convertToDTO(CompteWave null) retourne null (via réflexion)")
    void convertToDTO_compteWaveNull_returnsNull() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToDTO", CompteWave.class);
        method.setAccessible(true);
        Object result = method.invoke(waveService, (Object) null);
        assertThat(result).isNull();
    }

    @Test
    @DisplayName("convertToDTO(TransactionWave null) retourne null (via réflexion)")
    void convertToDTO_transactionWaveNull_returnsNull() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToDTO", TransactionWave.class);
        method.setAccessible(true);
        Object result = method.invoke(waveService, (Object) null);
        assertThat(result).isNull();
    }

    @Test
    @DisplayName("convertToEntity(CompteWaveDTO null) retourne null (via réflexion)")
    void convertToEntity_compteWaveDTONull_returnsNull() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToEntity", CompteWaveDTO.class);
        method.setAccessible(true);
        Object result = method.invoke(waveService, (Object) null);
        assertThat(result).isNull();
    }

    @Test
    @DisplayName("convertToEntity(TransactionWaveDTO null) retourne null (via réflexion)")
    void convertToEntity_transactionWaveDTONull_returnsNull() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToEntity", TransactionWaveDTO.class);
        method.setAccessible(true);
        Object result = method.invoke(waveService, (Object) null);
        assertThat(result).isNull();
    }

    @Test
    @DisplayName("convertToEntity TransactionWaveDTO avec nombreTentatives non null — valeur conservée")
    void convertToEntity_transactionWaveDTOWithNombreTentatives_preservesValue() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToEntity", TransactionWaveDTO.class);
        method.setAccessible(true);

        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-REF");
        dto.setNombreTentatives(5);
        dto.setCodeDevise("XOF");

        when(defaultsService.getDevise()).thenReturn("XOF");

        TransactionWave result = (TransactionWave) method.invoke(waveService, dto);
        assertThat(result).isNotNull();
        assertThat(result.getNombreTentatives()).isEqualTo(5);
    }

    @Test
    @DisplayName("convertToEntity CompteWaveDTO avec statut et environnement non null — valeurs conservées")
    void convertToEntity_compteWaveDTOWithStatutAndEnvironnement_preservesValues() throws Exception {
        java.lang.reflect.Method method = WaveService.class.getDeclaredMethod(
                "convertToEntity", CompteWaveDTO.class);
        method.setAccessible(true);

        CompteWaveDTO dto = new CompteWaveDTO();
        dto.setNumeroTelephone("776543210");
        dto.setStatutCompte(StatutCompteWave.VERIFIE); // non null → branch covered
        dto.setEnvironnement("PRODUCTION"); // non null → branch covered

        CompteWave result = (CompteWave) method.invoke(waveService, dto);
        assertThat(result).isNotNull();
        assertThat(result.getStatutCompte()).isEqualTo(StatutCompteWave.VERIFIE);
        assertThat(result.getEnvironnement()).isEqualTo("PRODUCTION");
    }

    // ─── Branche codeDevise == null dans convertToEntity(TransactionWaveDTO) ──

    @Test
    @DisplayName("creerTransactionWave avec codeDevise null — convertToEntity utilise devise par défaut (branche ligne 372)")
    void convertToEntity_transactionWaveDTO_codeDeviseNull_usesDefaultDevise() {
        TransactionWaveDTO dto = new TransactionWaveDTO();
        dto.setWaveTransactionId("WAVE-NO-DEVISE-" + UUID.randomUUID());
        dto.setStatutTransaction(StatutTransactionWave.INITIALISE);
        dto.setNombreTentatives(1);
        dto.setCodeDevise(null); // null → déclenche defaultsService.getDevise()

        when(defaultsService.getDevise()).thenReturn("XOF");
        when(keycloakService.getCurrentUserEmail()).thenReturn("test@test.com");
        doNothing().when(transactionWaveRepository).persist(any(TransactionWave.class));

        TransactionWaveDTO result = waveService.creerTransactionWave(dto);

        assertThat(result).isNotNull();
        assertThat(result.getCodeDevise()).isEqualTo("XOF");
    }
}
