package dev.lions.unionflow.server.repository;

import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.Optional;
import java.util.UUID;

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

/**
 * Tests unitaires purs pour DemandeAideRepository.
 * Couvre les cas limites de sumMontantDemandeByOrganisationId et sumMontantApprouveByOrganisationId.
 */
@DisplayName("DemandeAideRepository — tests unitaires (branches ternaires null)")
class DemandeAideRepositoryUnitTest {

    /**
     * Sous-classe concrète non gérée par CDI pour instancier DemandeAideRepository sans Quarkus.
     */
    static class TestDemandeAideRepository extends DemandeAideRepository {
        TestDemandeAideRepository(EntityManager em) {
            super();
            this.entityManager = em;
        }
    }

    private EntityManager em;
    private TestDemandeAideRepository repo;

    @BeforeEach
    void setUp() {
        em = mock(EntityManager.class);
        repo = new TestDemandeAideRepository(em);
    }

    @SuppressWarnings("unchecked")
    private TypedQuery<BigDecimal> mockBigDecimalQuery(BigDecimal returnValue) {
        TypedQuery<BigDecimal> q = mock(TypedQuery.class);
        when(q.setParameter(anyString(), any())).thenReturn(q);
        when(q.getSingleResult()).thenReturn(returnValue);
        return q;
    }

    @Test
    @DisplayName("sumMontantDemandeByOrganisationId: result null → retourne Optional.empty()")
    void sumMontantDemandeByOrganisationId_resultNull_returnsEmpty() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(null);
        when(em.createQuery(contains("COALESCE(SUM(d.montantDemande)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantDemandeByOrganisationId(UUID.randomUUID());
        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("sumMontantDemandeByOrganisationId: result > 0 → retourne Optional.present()")
    void sumMontantDemandeByOrganisationId_resultPositive_returnsPresent() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(BigDecimal.valueOf(5000));
        when(em.createQuery(contains("COALESCE(SUM(d.montantDemande)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantDemandeByOrganisationId(UUID.randomUUID());
        assertThat(result).isPresent();
        assertThat(result.get()).isEqualByComparingTo(BigDecimal.valueOf(5000));
    }

    @Test
    @DisplayName("sumMontantDemandeByOrganisationId: result = 0 → retourne Optional.empty()")
    void sumMontantDemandeByOrganisationId_resultZero_returnsEmpty() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(BigDecimal.ZERO);
        when(em.createQuery(contains("COALESCE(SUM(d.montantDemande)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantDemandeByOrganisationId(UUID.randomUUID());
        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("sumMontantApprouveByOrganisationId: result null → retourne Optional.empty()")
    void sumMontantApprouveByOrganisationId_resultNull_returnsEmpty() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(null);
        when(em.createQuery(contains("COALESCE(SUM(d.montantApprouve)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantApprouveByOrganisationId(UUID.randomUUID());
        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("sumMontantApprouveByOrganisationId: result > 0 → retourne Optional.present()")
    void sumMontantApprouveByOrganisationId_resultPositive_returnsPresent() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(BigDecimal.valueOf(3000));
        when(em.createQuery(contains("COALESCE(SUM(d.montantApprouve)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantApprouveByOrganisationId(UUID.randomUUID());
        assertThat(result).isPresent();
        assertThat(result.get()).isEqualByComparingTo(BigDecimal.valueOf(3000));
    }

    @Test
    @DisplayName("sumMontantApprouveByOrganisationId: result = 0 → retourne Optional.empty()")
    void sumMontantApprouveByOrganisationId_resultZero_returnsEmpty() {
        TypedQuery<BigDecimal> q = mockBigDecimalQuery(BigDecimal.ZERO);
        when(em.createQuery(contains("COALESCE(SUM(d.montantApprouve)"), eq(BigDecimal.class)))
                .thenReturn(q);

        Optional<BigDecimal> result = repo.sumMontantApprouveByOrganisationId(UUID.randomUUID());
        assertThat(result).isEmpty();
    }
}
