package dev.lions.unionflow.server.repository;

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

import dev.lions.unionflow.server.entity.Membre;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

/**
 * Tests d'intégration pour MembreRepository
 *
 * @author Lions Dev Team
 * @since 2025-01-10
 */
@QuarkusTest
@DisplayName("Tests d'intégration MembreRepository")
class MembreRepositoryIntegrationTest {

  @Inject MembreRepository membreRepository;

  private Membre membreTest;

  @BeforeEach
  @Transactional
  void setUp() {
    // Nettoyer la base de données
    membreRepository.deleteAll();

    // Créer un membre de test
    membreTest =
        Membre.builder()
            .numeroMembre("UF2025-TEST01")
            .prenom("Jean")
            .nom("Dupont")
            .email("jean.dupont@test.com")
            .telephone("221701234567")
            .dateNaissance(LocalDate.of(1990, 5, 15))
            .dateAdhesion(LocalDate.now())
            .actif(true)
            .build();

    membreRepository.persist(membreTest);
  }

  @Test
  @DisplayName("Test findByEmail - Membre existant")
  @Transactional
  void testFindByEmailExistant() {
    // When
    Optional<Membre> result = membreRepository.findByEmail("jean.dupont@test.com");

    // Then
    assertThat(result).isPresent();
    assertThat(result.get().getPrenom()).isEqualTo("Jean");
    assertThat(result.get().getNom()).isEqualTo("Dupont");
  }

  @Test
  @DisplayName("Test findByEmail - Membre inexistant")
  @Transactional
  void testFindByEmailInexistant() {
    // When
    Optional<Membre> result = membreRepository.findByEmail("inexistant@test.com");

    // Then
    assertThat(result).isEmpty();
  }

  @Test
  @DisplayName("Test findByNumeroMembre - Membre existant")
  @Transactional
  void testFindByNumeroMembreExistant() {
    // When
    Optional<Membre> result = membreRepository.findByNumeroMembre("UF2025-TEST01");

    // Then
    assertThat(result).isPresent();
    assertThat(result.get().getPrenom()).isEqualTo("Jean");
    assertThat(result.get().getNom()).isEqualTo("Dupont");
  }

  @Test
  @DisplayName("Test findByNumeroMembre - Membre inexistant")
  @Transactional
  void testFindByNumeroMembreInexistant() {
    // When
    Optional<Membre> result = membreRepository.findByNumeroMembre("UF2025-INEXISTANT");

    // Then
    assertThat(result).isEmpty();
  }

  @Test
  @DisplayName("Test findAllActifs - Seuls les membres actifs")
  @Transactional
  void testFindAllActifs() {
    // Given - Ajouter un membre inactif
    Membre membreInactif =
        Membre.builder()
            .numeroMembre("UF2025-TEST02")
            .prenom("Marie")
            .nom("Martin")
            .email("marie.martin@test.com")
            .telephone("221701234568")
            .dateNaissance(LocalDate.of(1985, 8, 20))
            .dateAdhesion(LocalDate.now())
            .actif(false)
            .build();
    membreRepository.persist(membreInactif);

    // When
    List<Membre> result = membreRepository.findAllActifs();

    // Then
    assertThat(result).hasSize(1);
    assertThat(result.get(0).getActif()).isTrue();
    assertThat(result.get(0).getPrenom()).isEqualTo("Jean");
  }

  @Test
  @DisplayName("Test countActifs - Nombre de membres actifs")
  @Transactional
  void testCountActifs() {
    // When
    long count = membreRepository.countActifs();

    // Then
    assertThat(count).isEqualTo(1);
  }

  @Test
  @DisplayName("Test findByNomOrPrenom - Recherche par nom")
  @Transactional
  void testFindByNomOrPrenomParNom() {
    // When
    List<Membre> result = membreRepository.findByNomOrPrenom("dupont");

    // Then
    assertThat(result).hasSize(1);
    assertThat(result.get(0).getNom()).isEqualTo("Dupont");
  }

  @Test
  @DisplayName("Test findByNomOrPrenom - Recherche par prénom")
  @Transactional
  void testFindByNomOrPrenomParPrenom() {
    // When
    List<Membre> result = membreRepository.findByNomOrPrenom("jean");

    // Then
    assertThat(result).hasSize(1);
    assertThat(result.get(0).getPrenom()).isEqualTo("Jean");
  }

  @Test
  @DisplayName("Test findByNomOrPrenom - Aucun résultat")
  @Transactional
  void testFindByNomOrPrenomAucunResultat() {
    // When
    List<Membre> result = membreRepository.findByNomOrPrenom("inexistant");

    // Then
    assertThat(result).isEmpty();
  }

  @Test
  @DisplayName("Test findByNomOrPrenom - Recherche insensible à la casse")
  @Transactional
  void testFindByNomOrPrenomCaseInsensitive() {
    // When
    List<Membre> result = membreRepository.findByNomOrPrenom("DUPONT");

    // Then
    assertThat(result).hasSize(1);
    assertThat(result.get(0).getNom()).isEqualTo("Dupont");
  }
}
