package dev.lions.unionflow.server.entity;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

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

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

@DisplayName("Versement")
class VersementTest {

    private static Membre newMembre() {
        Membre m = new Membre();
        m.setId(UUID.randomUUID());
        m.setNumeroMembre("M1");
        m.setPrenom("A");
        m.setNom("B");
        m.setEmail("a@test.com");
        m.setDateNaissance(java.time.LocalDate.now());
        return m;
    }

    @Test
    @DisplayName("getters/setters")
    void gettersSetters() {
        Versement v = new Versement();
        v.setNumeroReference("VRS-2026-001");
        v.setMontant(new BigDecimal("10000.00"));
        v.setCodeDevise("XOF");
        v.setMethodePaiement("WAVE");
        v.setStatutPaiement("CONFIRME");
        v.setDatePaiement(LocalDateTime.now());
        v.setNumeroTelephone("771234567");
        v.setMembre(newMembre());

        assertThat(v.getNumeroReference()).isEqualTo("VRS-2026-001");
        assertThat(v.getMontant()).isEqualByComparingTo("10000.00");
        assertThat(v.getCodeDevise()).isEqualTo("XOF");
        assertThat(v.getStatutPaiement()).isEqualTo("CONFIRME");
        assertThat(v.getNumeroTelephone()).isEqualTo("771234567");
    }

    @Test
    @DisplayName("genererNumeroReference commence par VRS-")
    void genererNumeroReference_startsWithVRS() {
        String ref = Versement.genererNumeroReference();
        assertThat(ref).startsWith("VRS-").isNotNull();
    }

    @Test
    @DisplayName("genererNumeroReference retourne des références uniques")
    void genererNumeroReference_unique() {
        String ref1 = Versement.genererNumeroReference();
        String ref2 = Versement.genererNumeroReference();
        assertThat(ref1).isNotEqualTo(ref2);
    }

    @Test
    @DisplayName("isConfirme — statut CONFIRME")
    void isConfirme_statutCONFIRME() {
        Versement v = buildMinimal();
        v.setStatutPaiement("CONFIRME");
        assertThat(v.isConfirme()).isTrue();
        assertThat(v.peutEtreModifie()).isFalse();
    }

    @Test
    @DisplayName("isConfirme — statut VALIDE (compatibilité)")
    void isConfirme_statutVALIDE() {
        Versement v = buildMinimal();
        v.setStatutPaiement("VALIDE");
        assertThat(v.isConfirme()).isTrue();
        assertThat(v.peutEtreModifie()).isFalse();
    }

    @Test
    @DisplayName("isConfirme — statut EN_ATTENTE")
    void isConfirme_statutEnAttente() {
        Versement v = buildMinimal();
        v.setStatutPaiement("EN_ATTENTE");
        assertThat(v.isConfirme()).isFalse();
        assertThat(v.peutEtreModifie()).isTrue();
    }

    @Test
    @DisplayName("peutEtreModifie — statut ANNULE")
    void peutEtreModifie_false_whenANNULE() {
        Versement v = buildMinimal();
        v.setStatutPaiement("ANNULE");
        assertThat(v.peutEtreModifie()).isFalse();
    }

    @Test
    @DisplayName("peutEtreModifie — statut EN_ATTENTE_VALIDATION")
    void peutEtreModifie_true_whenEnAttenteValidation() {
        Versement v = buildMinimal();
        v.setStatutPaiement("EN_ATTENTE_VALIDATION");
        assertThat(v.peutEtreModifie()).isTrue();
    }

    @Test
    @DisplayName("onCreate initialise reference, statut et datePaiement si null")
    void onCreate_initDefaults() {
        Versement v = new Versement();
        v.setMontant(BigDecimal.TEN);
        v.setCodeDevise("XOF");
        v.setMethodePaiement("WAVE");
        v.setMembre(newMembre());

        v.onCreate();

        assertThat(v.getNumeroReference()).startsWith("VRS-");
        assertThat(v.getStatutPaiement()).isEqualTo("EN_ATTENTE");
        assertThat(v.getDatePaiement()).isNotNull();
    }

    @Test
    @DisplayName("onCreate conserve la référence existante")
    void onCreate_preservesExistingReference() {
        Versement v = buildMinimal();
        v.setNumeroReference("VRS-CUSTOM-001");
        v.onCreate();
        assertThat(v.getNumeroReference()).isEqualTo("VRS-CUSTOM-001");
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        Membre m = newMembre();
        Versement a = buildMinimal();
        a.setId(id);
        a.setMembre(m);
        Versement b = buildMinimal();
        b.setId(id);
        b.setMembre(m);
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        assertThat(buildMinimal().toString()).isNotNull().isNotEmpty();
    }

    private Versement buildMinimal() {
        Versement v = new Versement();
        v.setNumeroReference("VRS-2026-TEST");
        v.setMontant(BigDecimal.ONE);
        v.setCodeDevise("XOF");
        v.setMethodePaiement("WAVE");
        v.setStatutPaiement("EN_ATTENTE");
        v.setMembre(newMembre());
        return v;
    }
}
