package dev.lions.unionflow.server.entity;

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

import java.time.LocalDate;
import java.util.UUID;

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

@DisplayName("MembreRole")
class MembreRoleTest {

    private static MembreOrganisation newMembreOrganisation() {
        Membre m = new Membre();
        m.setId(UUID.randomUUID());
        m.setNumeroMembre("M1");
        m.setPrenom("A");
        m.setNom("B");
        m.setEmail("a@test.com");
        m.setDateNaissance(LocalDate.now());
        Organisation o = new Organisation();
        o.setId(UUID.randomUUID());
        MembreOrganisation mo = new MembreOrganisation();
        mo.setMembre(m);
        mo.setOrganisation(o);
        return mo;
    }

    private static Role newRole() {
        Role r = new Role();
        r.setId(UUID.randomUUID());
        r.setCode("ADMIN");
        r.setLibelle("Administrateur");
        return r;
    }

    @Test
    @DisplayName("getters/setters")
    void gettersSetters() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setOrganisation(new Organisation());
        mr.setRole(newRole());
        mr.setDateDebut(LocalDate.now());
        mr.setCommentaire("Attribution");

        assertThat(mr.getDateDebut()).isNotNull();
        assertThat(mr.getCommentaire()).isEqualTo("Attribution");
    }

    @Test
    @DisplayName("isActif: false si dateDebut dans le futur")
    void isActif_false_debutFutur() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        mr.setDateDebut(LocalDate.now().plusDays(10));
        assertThat(mr.isActif()).isFalse();
    }

    @Test
    @DisplayName("isActif: false si actif=false")
    void isActif_false_whenActifFalse() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(false);
        mr.setDateDebut(LocalDate.now().minusDays(1));
        assertThat(mr.isActif()).isFalse();
    }

    @Test
    @DisplayName("isActif: false si dateFin dans le passé")
    void isActif_false_dateFinExpiree() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        mr.setDateDebut(LocalDate.now().minusDays(10));
        mr.setDateFin(LocalDate.now().minusDays(1));
        assertThat(mr.isActif()).isFalse();
    }

    @Test
    @DisplayName("isActif: true si dans la période")
    void isActif_true() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        mr.setDateDebut(LocalDate.now().minusDays(1));
        mr.setDateFin(null);
        assertThat(mr.isActif()).isTrue();
    }

    @Test
    @DisplayName("equals et hashCode")
    void equalsHashCode() {
        UUID id = UUID.randomUUID();
        MembreOrganisation mo = newMembreOrganisation();
        Role r = newRole();
        MembreRole a = new MembreRole();
        a.setId(id);
        a.setMembreOrganisation(mo);
        a.setRole(r);
        MembreRole b = new MembreRole();
        b.setId(id);
        b.setMembreOrganisation(mo);
        b.setRole(r);
        assertThat(a).isEqualTo(b);
        assertThat(a.hashCode()).isEqualTo(b.hashCode());
    }

    @Test
    @DisplayName("toString non null")
    void toString_nonNull() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        assertThat(mr.toString()).isNotNull().isNotEmpty();
    }

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

    @Test
    @DisplayName("isActif: dateDebut null → condition L76 false (null short-circuit) → continue vers dateFin")
    void isActif_dateDebutNull_branchNullShortCircuit() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        mr.setDateDebut(null); // null → dateDebut != null = false → skip if body at L76
        mr.setDateFin(null);   // null → dateFin != null = false → skip if body at L79
        // → return true
        assertThat(mr.isActif()).isTrue();
    }

    /**
     * L72 branch manquante : getActif() == null → Boolean.TRUE.equals(null) = false
     * → !false = true → returns false
     */
    @Test
    @DisplayName("isActif: actif null → Boolean.TRUE.equals(null) false → retourne false")
    void isActif_actifNull_returnsFalse() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        // actif n'est pas défini (null)
        mr.setDateDebut(LocalDate.now().minusDays(1));
        assertThat(mr.isActif()).isFalse();
    }

    @Test
    @DisplayName("isActif: dateDebut non null mais passée → ne retourne pas false (branche false isBefore)")
    void isActif_dateDebut_notNull_notBefore_continues() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        // dateDebut dans le passé → isBefore(dateDebut) est false → on continue
        mr.setDateDebut(LocalDate.now().minusDays(5));
        mr.setDateFin(null);
        assertThat(mr.isActif()).isTrue();
    }

    /**
     * L79 branch manquante : dateFin != null mais today <= dateFin (NOT after)
     * → `dateFin != null && aujourdhui.isAfter(dateFin)` → false → continue → return true
     */
    @Test
    @DisplayName("isActif: dateFin non null mais pas encore dépassée → ne retourne pas false (branche false isAfter)")
    void isActif_dateFin_notNull_notAfter_returnsTrue() {
        MembreRole mr = new MembreRole();
        mr.setMembreOrganisation(newMembreOrganisation());
        mr.setRole(newRole());
        mr.setActif(true);
        mr.setDateDebut(LocalDate.now().minusDays(5));
        // dateFin dans le futur → isAfter(dateFin) est false → retourne true
        mr.setDateFin(LocalDate.now().plusDays(5));
        assertThat(mr.isActif()).isTrue();
    }
}
