package dev.lions.unionflow.server.entity;

import dev.lions.unionflow.server.api.enums.solidarite.StatutAide;
import dev.lions.unionflow.server.api.enums.solidarite.StatutValidationEtape;
import dev.lions.unionflow.server.api.enums.solidarite.TypeAide;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.UUID;

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

@DisplayName("ValidationEtapeDemande")
class ValidationEtapeDemandeTest {

    private static DemandeAide newDemandeAide() {
        DemandeAide d = new DemandeAide();
        d.setId(UUID.randomUUID());
        d.setTitre("Aide");
        d.setDescription("Desc");
        d.setTypeAide(TypeAide.AIDE_FRAIS_MEDICAUX);
        d.setStatut(StatutAide.EN_ATTENTE);
        d.setMontantDemande(java.math.BigDecimal.ONE);
        d.setDateDemande(LocalDateTime.now());
        return d;
    }

    @Test
    @DisplayName("getters/setters")
    void gettersSetters() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.EN_ATTENTE);
        v.setDateValidation(LocalDateTime.now());
        v.setCommentaire("OK");

        assertThat(v.getEtapeNumero()).isEqualTo(1);
        assertThat(v.getStatut()).isEqualTo(StatutValidationEtape.EN_ATTENTE);
        assertThat(v.getCommentaire()).isEqualTo("OK");
    }

    @Test
    @DisplayName("estEnAttente et estFinalisee")
    void estEnAttente_estFinalisee() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.EN_ATTENTE);
        assertThat(v.estEnAttente()).isTrue();
        assertThat(v.estFinalisee()).isFalse();
        v.setStatut(StatutValidationEtape.APPROUVEE);
        assertThat(v.estEnAttente()).isFalse();
        assertThat(v.estFinalisee()).isTrue();
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        DemandeAide d = newDemandeAide();
        ValidationEtapeDemande a = new ValidationEtapeDemande();
        a.setId(id);
        a.setDemandeAide(d);
        a.setEtapeNumero(1);
        a.setStatut(StatutValidationEtape.EN_ATTENTE);
        ValidationEtapeDemande b = new ValidationEtapeDemande();
        b.setId(id);
        b.setDemandeAide(d);
        b.setEtapeNumero(1);
        b.setStatut(StatutValidationEtape.EN_ATTENTE);
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.EN_ATTENTE);
        assertThat(v.toString()).isNotNull().isNotEmpty();
    }

    @Test
    @DisplayName("estFinalisee: true pour REJETEE")
    void estFinalisee_rejetee() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.REJETEE);
        assertThat(v.estFinalisee()).isTrue();
    }

    @Test
    @DisplayName("estFinalisee: true pour DELEGUEE")
    void estFinalisee_deleguee() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.DELEGUEE);
        assertThat(v.estFinalisee()).isTrue();
    }

    @Test
    @DisplayName("estFinalisee: true pour EXPIREE")
    void estFinalisee_expiree() {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.EXPIREE);
        assertThat(v.estFinalisee()).isTrue();
    }

    @Test
    @DisplayName("onCreate (PrePersist) - statut null est initialisé à EN_ATTENTE via réflexion")
    void onCreate_withNullStatut_setsEnAttente() throws Exception {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);

        // Forcer statut à null via le champ Lombok
        Field statutField = ValidationEtapeDemande.class.getDeclaredField("statut");
        statutField.setAccessible(true);
        statutField.set(v, null);
        assertThat(v.getStatut()).isNull();

        Method onCreate = ValidationEtapeDemande.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(v);

        assertThat(v.getStatut()).isEqualTo(StatutValidationEtape.EN_ATTENTE);
    }

    @Test
    @DisplayName("onCreate (PrePersist) - statut déjà défini n'est pas écrasé")
    void onCreate_withExistingStatut_keepsStatut() throws Exception {
        ValidationEtapeDemande v = new ValidationEtapeDemande();
        v.setDemandeAide(newDemandeAide());
        v.setEtapeNumero(1);
        v.setStatut(StatutValidationEtape.APPROUVEE);

        Method onCreate = ValidationEtapeDemande.class.getDeclaredMethod("onCreate");
        onCreate.setAccessible(true);
        onCreate.invoke(v);

        assertThat(v.getStatut()).isEqualTo(StatutValidationEtape.APPROUVEE);
    }
}
