package dev.lions.unionflow.server.api.dto.abonnement.response;

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

import dev.lions.unionflow.server.api.enums.abonnement.StatutAbonnement;
import java.time.LocalDate;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires pour AbonnementResponse.
 * Couvre toutes les méthodes utilitaires avec toutes les branches.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-03-01
 */
@DisplayName("Tests AbonnementResponse")
class AbonnementResponseTest {

    @Nested
    @DisplayName("isExpire")
    class IsExpire {

        @Test
        @DisplayName("retourne true quand statut EXPIRE")
        void testStatutExpire() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.EXPIRE)
                .dateFin(LocalDate.now().plusDays(10)) // même avec dateFin dans le futur
                .build();

            assertThat(response.isExpire()).isTrue();
        }

        @Test
        @DisplayName("retourne true quand dateFin dans le passé")
        void testDateFinPassee() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.ACTIF) // statut != EXPIRE
                .dateFin(LocalDate.now().minusDays(5))
                .build();

            assertThat(response.isExpire()).isTrue();
        }

        @Test
        @DisplayName("retourne false quand statut != EXPIRE et dateFin null")
        void testStatutActifDateFinNull() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.ACTIF)
                .dateFin(null)
                .build();

            assertThat(response.isExpire()).isFalse();
        }

        @Test
        @DisplayName("retourne false quand statut != EXPIRE et dateFin future")
        void testStatutActifDateFinFuture() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.ACTIF)
                .dateFin(LocalDate.now().plusDays(10))
                .build();

            assertThat(response.isExpire()).isFalse();
        }
    }

    @Nested
    @DisplayName("isExpirationProche")
    class IsExpirationProche {

        @Test
        @DisplayName("retourne true quand joursRestants entre 0 et 30")
        void testExpirationProche() {
            AbonnementResponse response = AbonnementResponse.builder()
                .dateFin(LocalDate.now().plusDays(15))
                .build();

            assertThat(response.isExpirationProche()).isTrue();
        }

        @Test
        @DisplayName("retourne false quand joursRestants > 30")
        void testExpirationLoin() {
            AbonnementResponse response = AbonnementResponse.builder()
                .dateFin(LocalDate.now().plusDays(60))
                .build();

            assertThat(response.isExpirationProche()).isFalse();
        }

        @Test
        @DisplayName("retourne false quand joursRestants < 0 (dateFin null)")
        void testDateFinNull() {
            AbonnementResponse response = AbonnementResponse.builder()
                .dateFin(null)
                .build();

            assertThat(response.isExpirationProche()).isFalse();
        }

        @Test
        @DisplayName("retourne true quand joursRestants = 0 (déjà expiré)")
        void testExpireAujourdhui() {
            AbonnementResponse response = AbonnementResponse.builder()
                .dateFin(LocalDate.now().minusDays(1))
                .build();

            assertThat(response.isExpirationProche()).isTrue(); // joursRestants = 0, et 0 >= 0 && 0 <= 30
        }
    }

    @Nested
    @DisplayName("peutEtreRenouvele")
    class PeutEtreRenouvele {

        @Test
        @DisplayName("retourne true quand renouvellement auto et non expiré")
        void testRenouvellable() {
            AbonnementResponse response = AbonnementResponse.builder()
                .renouvellementAutomatique(true)
                .statut(StatutAbonnement.ACTIF)
                .dateFin(LocalDate.now().plusDays(30))
                .build();

            assertThat(response.peutEtreRenouvele()).isTrue();
        }

        @Test
        @DisplayName("retourne false quand renouvellement auto false")
        void testRenouvellementAutoFalse() {
            AbonnementResponse response = AbonnementResponse.builder()
                .renouvellementAutomatique(false)
                .statut(StatutAbonnement.ACTIF)
                .dateFin(LocalDate.now().plusDays(30))
                .build();

            assertThat(response.peutEtreRenouvele()).isFalse();
        }

        @Test
        @DisplayName("retourne false quand renouvellement auto null")
        void testRenouvellementAutoNull() {
            AbonnementResponse response = AbonnementResponse.builder()
                .renouvellementAutomatique(null)
                .statut(StatutAbonnement.ACTIF)
                .dateFin(LocalDate.now().plusDays(30))
                .build();

            assertThat(response.peutEtreRenouvele()).isFalse();
        }

        @Test
        @DisplayName("retourne false quand abonnement expiré")
        void testExpire() {
            AbonnementResponse response = AbonnementResponse.builder()
                .renouvellementAutomatique(true)
                .statut(StatutAbonnement.EXPIRE)
                .dateFin(LocalDate.now().minusDays(10))
                .build();

            assertThat(response.peutEtreRenouvele()).isFalse();
        }
    }

    @Nested
    @DisplayName("Autres méthodes utilitaires")
    class AutresMethodes {

        @Test
        @DisplayName("isActive retourne true pour ACTIF")
        void testIsActive() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.ACTIF)
                .build();

            assertThat(response.isActive()).isTrue();
        }

        @Test
        @DisplayName("isSuspendu retourne true pour SUSPENDU")
        void testIsSuspendu() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.SUSPENDU)
                .build();

            assertThat(response.isSuspendu()).isTrue();
        }

        @Test
        @DisplayName("getStatutLibelle retourne le nom du statut")
        void testGetStatutLibelle() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(StatutAbonnement.ACTIF)
                .build();

            assertThat(response.getStatutLibelle()).isEqualTo("ACTIF");
        }

        @Test
        @DisplayName("getStatutLibelle retourne INCONNU quand statut null")
        void testGetStatutLibelleNull() {
            AbonnementResponse response = AbonnementResponse.builder()
                .statut(null)
                .build();

            assertThat(response.getStatutLibelle()).isEqualTo("INCONNU");
        }
    }
}
