package dev.lions.unionflow.server.repository;

import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.TransactionApproval;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.TestTransaction;
import jakarta.inject.Inject;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

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

@QuarkusTest
class TransactionApprovalRepositoryTest {

    @Inject
    TransactionApprovalRepository transactionApprovalRepository;

    @Inject
    OrganisationRepository organisationRepository;

    private Organisation newOrganisation() {
        Organisation o = new Organisation();
        o.setNom("Org Approval " + UUID.randomUUID());
        o.setTypeOrganisation("ASSOCIATION");
        o.setStatut("ACTIVE");
        o.setEmail("approval-org-" + UUID.randomUUID() + "@test.com");
        o.setActif(true);
        organisationRepository.persist(o);
        return o;
    }

    private TransactionApproval newApproval(Organisation org, String status) {
        return TransactionApproval.builder()
                .transactionId(UUID.randomUUID())
                .transactionType("CONTRIBUTION")
                .amount(BigDecimal.valueOf(5000))
                .currency("XOF")
                .requesterId(UUID.randomUUID())
                .requesterName("Test Requester")
                .organisation(org)
                .requiredLevel("LEVEL1")
                .status(status)
                .createdAt(LocalDateTime.now())
                .expiresAt(LocalDateTime.now().plusDays(7))
                .build();
    }

    // --- findHistory() missed branches ---

    @Test
    @TestTransaction
    @DisplayName("findHistory sans aucun filtre optionnel retourne une liste")
    void findHistory_noFilters_returnsList() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "PENDING");
        transactionApprovalRepository.persist(approval);

        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(), null, null, null);
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findHistory avec startDate seulement couvre la branche startDate != null et endDate == null")
    void findHistory_startDateOnly_returnsList() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "APPROVED");
        transactionApprovalRepository.persist(approval);

        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(), LocalDateTime.now().minusDays(1), null, null);
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findHistory avec endDate seulement couvre la branche endDate != null et startDate == null")
    void findHistory_endDateOnly_returnsList() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "APPROVED");
        transactionApprovalRepository.persist(approval);

        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(), null, LocalDateTime.now().plusDays(1), null);
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findHistory avec status couvre la branche status != null")
    void findHistory_withStatus_returnsList() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "PENDING");
        transactionApprovalRepository.persist(approval);

        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(), null, null, "PENDING");
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findHistory avec tous les filtres couvre toutes les branches true")
    void findHistory_allFilters_returnsList() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "APPROVED");
        transactionApprovalRepository.persist(approval);

        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(),
                LocalDateTime.now().minusDays(1),
                LocalDateTime.now().plusDays(1),
                "APPROVED");
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    // ── Branch coverage manquantes ─────────────────────────────────────────

    /**
     * L109 + L124 branch manquante : status != null mais status.isEmpty() → false
     * → `if (status != null && !status.isEmpty())` → false (status est "")
     * → la condition est évaluée mais isEmpty() court-circuite
     */
    @Test
    @TestTransaction
    @DisplayName("findHistory avec status vide (empty) couvre la branche status != null && isEmpty")
    void findHistory_emptyStatus_treatedAsNoFilter() {
        Organisation org = newOrganisation();
        TransactionApproval approval = newApproval(org, "PENDING");
        transactionApprovalRepository.persist(approval);

        // status = "" → !status.isEmpty() est false → branche false du && → pas filtré par status
        List<TransactionApproval> list = transactionApprovalRepository.findHistory(
                org.getId(), null, null, "");
        assertThat(list).isNotNull();
        assertThat(list).isNotEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findPending retourne une liste")
    void findPending_returnsList() {
        List<TransactionApproval> list = transactionApprovalRepository.findPending();
        assertThat(list).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("findByTransactionId inexistant retourne empty")
    void findByTransactionId_inexistant_returnsEmpty() {
        Optional<TransactionApproval> opt = transactionApprovalRepository.findByTransactionId(UUID.randomUUID());
        assertThat(opt).isEmpty();
    }

    @Test
    @TestTransaction
    @DisplayName("findExpired retourne une liste")
    void findExpired_returnsList() {
        List<TransactionApproval> list = transactionApprovalRepository.findExpired();
        assertThat(list).isNotNull();
    }

    @Test
    @TestTransaction
    @DisplayName("countPendingByOrganisation retourne un nombre >= 0")
    void countPendingByOrganisation_returnsNonNegative() {
        long count = transactionApprovalRepository.countPendingByOrganisation(UUID.randomUUID());
        assertThat(count).isGreaterThanOrEqualTo(0L);
    }

    @Test
    @TestTransaction
    @DisplayName("findPendingByOrganisation retourne une liste non-null")
    void findPendingByOrganisation_returnsList() {
        List<TransactionApproval> list = transactionApprovalRepository.findPendingByOrganisation(UUID.randomUUID());
        assertThat(list).isNotNull();
    }
}
