package dev.lions.unionflow.server.repository.mutuelle.parts;

import dev.lions.unionflow.server.api.enums.mutuelle.parts.TypeTransactionPartsSociales;
import dev.lions.unionflow.server.entity.mutuelle.parts.TransactionPartsSociales;
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.List;
import java.util.UUID;

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

@DisplayName("TransactionPartsSocialesRepository — tests unitaires")
class TransactionPartsSocialesRepositoryTest {

    static class TestableTransactionPartsSocialesRepository
            extends TransactionPartsSocialesRepository {
        // instanciation sans CDI
    }

    private TransactionPartsSocialesRepository repo;

    @BeforeEach
    void setUp() {
        repo = spy(new TestableTransactionPartsSocialesRepository());
    }

    @Test
    @DisplayName("classExists : instanciation possible sans CDI")
    void classExists() {
        assertThat(new TestableTransactionPartsSocialesRepository()).isNotNull();
    }

    // ─── findByCompte ─────────────────────────────────────────────────────────

    @Test
    @DisplayName("findByCompte : retourne liste vide si aucune transaction pour ce compte")
    void findByCompte_noResult_returnsEmpty() {
        doReturn(List.of()).when(repo).list(anyString(), any(UUID.class));

        List<TransactionPartsSociales> result = repo.findByCompte(UUID.randomUUID());

        assertThat(result).isEmpty();
    }

    @Test
    @DisplayName("findByCompte : retourne les transactions du compte triées par date décroissante")
    void findByCompte_withResult_returnsList() {
        TransactionPartsSociales t1 = TransactionPartsSociales.builder()
                .typeTransaction(TypeTransactionPartsSociales.SOUSCRIPTION)
                .nombreParts(5)
                .montant(new BigDecimal("25000"))
                .build();
        TransactionPartsSociales t2 = TransactionPartsSociales.builder()
                .typeTransaction(TypeTransactionPartsSociales.PAIEMENT_DIVIDENDE)
                .nombreParts(1)
                .montant(new BigDecimal("1250"))
                .build();
        doReturn(List.of(t1, t2)).when(repo).list(anyString(), any(UUID.class));

        List<TransactionPartsSociales> result = repo.findByCompte(UUID.randomUUID());

        assertThat(result).hasSize(2).containsExactly(t1, t2);
    }

    @Test
    @DisplayName("findByCompte : UUID null produit un appel list avec null")
    void findByCompte_nullId_stillCallsList() {
        doReturn(List.of()).when(repo).list(anyString(), (Object) isNull());

        List<TransactionPartsSociales> result = repo.findByCompte(null);

        assertThat(result).isNotNull().isEmpty();
    }

    @Test
    @DisplayName("findByCompte : retourne une seule transaction si une seule existe")
    void findByCompte_singleTransaction_returnsSingleton() {
        TransactionPartsSociales t = TransactionPartsSociales.builder()
                .typeTransaction(TypeTransactionPartsSociales.CORRECTION)
                .nombreParts(2)
                .montant(new BigDecimal("10000"))
                .motif("Correction administrative")
                .build();
        doReturn(List.of(t)).when(repo).list(anyString(), any(UUID.class));

        List<TransactionPartsSociales> result = repo.findByCompte(UUID.randomUUID());

        assertThat(result).hasSize(1);
        assertThat(result.get(0).getTypeTransaction())
                .isEqualTo(TypeTransactionPartsSociales.CORRECTION);
    }
}
