package dev.lions.unionflow.server.entity;

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

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

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

@DisplayName("InscriptionEvenement")
class InscriptionEvenementTest {

    private static Membre newMembre() {
        Membre m = new Membre();
        m.setId(UUID.randomUUID());
        return m;
    }

    private static Evenement newEvenement() {
        Evenement e = new Evenement();
        e.setId(UUID.randomUUID());
        e.setTitre("Ev");
        e.setDateDebut(LocalDateTime.now());
        return e;
    }

    @Test
    @DisplayName("getters/setters")
    void gettersSetters() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        i.setDateInscription(LocalDateTime.now());
        i.setStatut(InscriptionEvenement.StatutInscription.CONFIRMEE.name());
        i.setCommentaire("OK");

        assertThat(i.getStatut()).isEqualTo("CONFIRMEE");
        assertThat(i.getCommentaire()).isEqualTo("OK");
    }

    @Test
    @DisplayName("isConfirmee, isEnAttente, isAnnulee")
    void statutBooleans() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        i.setStatut(InscriptionEvenement.StatutInscription.CONFIRMEE.name());
        assertThat(i.isConfirmee()).isTrue();
        assertThat(i.isEnAttente()).isFalse();
        i.setStatut(InscriptionEvenement.StatutInscription.EN_ATTENTE.name());
        assertThat(i.isEnAttente()).isTrue();
        i.setStatut(InscriptionEvenement.StatutInscription.ANNULEE.name());
        assertThat(i.isAnnulee()).isTrue();
    }

    @Test
    @DisplayName("confirmer, annuler, mettreEnAttente, refuser")
    void actionsStatut() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        i.setStatut(InscriptionEvenement.StatutInscription.EN_ATTENTE.name());
        i.confirmer();
        assertThat(i.getStatut()).isEqualTo("CONFIRMEE");
        i.annuler("Annulé");
        assertThat(i.getStatut()).isEqualTo("ANNULEE");
        assertThat(i.getCommentaire()).isEqualTo("Annulé");
        i.mettreEnAttente("En attente");
        assertThat(i.getStatut()).isEqualTo("EN_ATTENTE");
        i.refuser("Refusé");
        assertThat(i.getStatut()).isEqualTo("REFUSEE");
    }

    @Test
    @DisplayName("statut par défaut CONFIRMEE")
    void statutDefaut() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        assertThat(i.getStatut()).isEqualTo("CONFIRMEE");
    }

    @Test
    @DisplayName("statut enum StatutInscription")
    void statutInscriptionEnum() {
        assertThat(InscriptionEvenement.StatutInscription.CONFIRMEE.name()).isEqualTo("CONFIRMEE");
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        Membre m = newMembre();
        Evenement e = newEvenement();
        LocalDateTime dt = LocalDateTime.now();
        InscriptionEvenement a = new InscriptionEvenement();
        a.setId(id);
        a.setMembre(m);
        a.setEvenement(e);
        a.setDateInscription(dt);
        a.setStatut("CONFIRMEE");
        InscriptionEvenement b = new InscriptionEvenement();
        b.setId(id);
        b.setMembre(m);
        b.setEvenement(e);
        b.setDateInscription(dt);
        b.setStatut("CONFIRMEE");
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        assertThat(i.toString()).isNotNull().isNotEmpty();
    }

    @Test
    @DisplayName("preUpdate ne lève pas d'exception")
    void preUpdate_doesNotThrow() throws Exception {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(newMembre());
        i.setEvenement(newEvenement());
        i.setStatut(InscriptionEvenement.StatutInscription.CONFIRMEE.name());
        Method preUpdate = InscriptionEvenement.class.getDeclaredMethod("preUpdate");
        preUpdate.setAccessible(true);
        assertThatCode(() -> preUpdate.invoke(i)).doesNotThrowAnyException();
    }

    @Test
    @DisplayName("toString avec membre et evenement null")
    void toString_nullMemberAndEvenement() {
        InscriptionEvenement i = new InscriptionEvenement();
        i.setMembre(null);
        i.setEvenement(null);
        i.setStatut("CONFIRMEE");
        String s = i.toString();
        assertThat(s).isNotNull().contains("null");
    }
}
