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

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

import java.time.LocalDateTime;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import dev.lions.unionflow.server.api.enums.solidarite.StatutProposition;

/**
 * Tests unitaires pour PropositionAideResponse.
 * Couvre isActiveEtDisponible, isExpiree, peutAccepterBeneficiaires,
 * getPourcentageCapaciteUtilisee, getPlacesRestantes.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests PropositionAideResponse")
class PropositionAideResponseTest {

  @Nested
  @DisplayName("isExpiree")
  class IsExpiree {

    @Test
    @DisplayName("retourne false quand dateExpiration null")
    void testNull() {
      PropositionAideResponse r = PropositionAideResponse.builder().dateExpiration(null).build();
      assertThat(r.isExpiree()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand date expiration passée")
    void testExpiree() {
      LocalDateTime hier = LocalDateTime.now().minusHours(1);
      PropositionAideResponse r = PropositionAideResponse.builder().dateExpiration(hier).build();
      assertThat(r.isExpiree()).isTrue();
    }

    @Test
    @DisplayName("retourne false quand date expiration future")
    void testNonExpiree() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder().dateExpiration(demain).build();
      assertThat(r.isExpiree()).isFalse();
    }
  }

  @Nested
  @DisplayName("isActiveEtDisponible")
  class IsActiveEtDisponible {

    @Test
    @DisplayName("retourne false quand statut pas ACTIVE")
    void testStatutNonActive() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.BROUILLON)
          .estDisponible(true)
          .dateExpiration(demain)
          .build();
      assertThat(r.isActiveEtDisponible()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand estDisponible false")
    void testNonDisponible() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.ACTIVE)
          .estDisponible(false)
          .dateExpiration(demain)
          .build();
      assertThat(r.isActiveEtDisponible()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand expirée")
    void testExpiree() {
      LocalDateTime hier = LocalDateTime.now().minusHours(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.ACTIVE)
          .estDisponible(true)
          .dateExpiration(hier)
          .build();
      assertThat(r.isActiveEtDisponible()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand ACTIVE, disponible et non expirée")
    void testActiveDisponible() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.ACTIVE)
          .estDisponible(true)
          .dateExpiration(demain)
          .build();
      assertThat(r.isActiveEtDisponible()).isTrue();
    }
  }

  @Nested
  @DisplayName("peutAccepterBeneficiaires")
  class PeutAccepterBeneficiaires {

    @Test
    @DisplayName("retourne false quand pas active et disponible")
    void testNonActive() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.SUSPENDUE)
          .estDisponible(true)
          .dateExpiration(LocalDateTime.now().plusDays(1))
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(5)
          .build();
      assertThat(r.peutAccepterBeneficiaires()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand capacité pleine")
    void testCapacitePleine() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.ACTIVE)
          .estDisponible(true)
          .dateExpiration(demain)
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(10)
          .build();
      assertThat(r.peutAccepterBeneficiaires()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand active, disponible et places restantes")
    void testPeutAccepter() {
      LocalDateTime demain = LocalDateTime.now().plusDays(1);
      PropositionAideResponse r = PropositionAideResponse.builder()
          .statut(StatutProposition.ACTIVE)
          .estDisponible(true)
          .dateExpiration(demain)
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(3)
          .build();
      assertThat(r.peutAccepterBeneficiaires()).isTrue();
    }
  }

  @Nested
  @DisplayName("getPourcentageCapaciteUtilisee")
  class GetPourcentageCapaciteUtilisee {

    @Test
    @DisplayName("retourne 100 quand nombreMaxBeneficiaires null")
    void testMaxNull() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(null)
          .nombreBeneficiairesAides(5)
          .build();
      assertThat(r.getPourcentageCapaciteUtilisee()).isEqualTo(100.0);
    }

    @Test
    @DisplayName("retourne 100 quand nombreMaxBeneficiaires 0")
    void testMaxZero() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(0)
          .nombreBeneficiairesAides(0)
          .build();
      assertThat(r.getPourcentageCapaciteUtilisee()).isEqualTo(100.0);
    }

    @Test
    @DisplayName("retourne pourcentage calculé")
    void testCalcul() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(3)
          .build();
      assertThat(r.getPourcentageCapaciteUtilisee()).isEqualTo(30.0);
    }
  }

  @Nested
  @DisplayName("getPlacesRestantes")
  class GetPlacesRestantes {

    @Test
    @DisplayName("retourne 0 quand nombreMaxBeneficiaires null")
    void testMaxNull() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(null)
          .build();
      assertThat(r.getPlacesRestantes()).isEqualTo(0);
    }

    @Test
    @DisplayName("retourne max quand nombreBeneficiairesAides null")
    void testAidesNull() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(null)
          .build();
      assertThat(r.getPlacesRestantes()).isEqualTo(10);
    }

    @Test
    @DisplayName("retourne différence positive")
    void testDifference() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(4)
          .build();
      assertThat(r.getPlacesRestantes()).isEqualTo(6);
    }

    @Test
    @DisplayName("retourne 0 quand plus de bénéficiaires que max (cap)")
    void testCap() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .nombreMaxBeneficiaires(10)
          .nombreBeneficiairesAides(15)
          .build();
      assertThat(r.getPlacesRestantes()).isEqualTo(0);
    }
  }

  @Nested
  @DisplayName("Builder et getters")
  class BuilderEtGetters {

    @Test
    @DisplayName("builder remplit les champs")
    void testBuilder() {
      PropositionAideResponse r = PropositionAideResponse.builder()
          .numeroReference("PROP-001")
          .titre("Titre")
          .statut(StatutProposition.ACTIVE)
          .estDisponible(true)
          .build();
      assertThat(r.getNumeroReference()).isEqualTo("PROP-001");
      assertThat(r.getTitre()).isEqualTo("Titre");
      assertThat(r.getStatut()).isEqualTo(StatutProposition.ACTIVE);
      assertThat(r.getEstDisponible()).isTrue();
    }
  }
}
