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

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

import dev.lions.unionflow.server.api.dto.solidarite.EvaluationAideDTO.StatutEvaluation;
import dev.lions.unionflow.server.api.dto.solidarite.EvaluationAideDTO.TypeEvaluation;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.EnumSource;
import org.junit.jupiter.params.provider.ValueSource;

@DisplayName("Tests pour EvaluationAideDTO")
class EvaluationAideDTOTest {

  @Test
  @DisplayName("Test de base - classe peut être instanciée")
  void testClasseInstanciable() {
    EvaluationAideDTO dto = new EvaluationAideDTO();
    assertThat(dto).isNotNull();
  }

  @Nested
  @DisplayName("Tests de construction")
  class ConstructionTests {

    @Test
    @DisplayName("Constructeur par défaut")
    void testConstructeurParDefaut() {
      EvaluationAideDTO dto = new EvaluationAideDTO();

      assertThat(dto).isNotNull();
      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      assertThat(dto.getDateCreation()).isNotNull();
      assertThat(dto.getDateModification()).isNotNull();
      assertThat(dto.getEstPublique()).isTrue();
      assertThat(dto.getEstAnonyme()).isFalse();
      assertThat(dto.getEstVerifiee()).isFalse();
      assertThat(dto.getRecommande()).isTrue();
      assertThat(dto.getAideUtile()).isTrue();
      assertThat(dto.getProblemeResolu()).isTrue();
      assertThat(dto.getStatut()).isEqualTo(StatutEvaluation.ACTIVE);
      assertThat(dto.getNombreUtile()).isEqualTo(0);
      assertThat(dto.getNombreSignalements()).isEqualTo(0);
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .id("id-123")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .evaluateurNom("Évaluateur Test")
          .roleEvaluateur("beneficiaire")
          .typeEvaluation(TypeEvaluation.SATISFACTION_BENEFICIAIRE)
          .noteGlobale(4.5)
          .commentairePrincipal("Très satisfait")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .dateCreation(dateCreation)
          .build();

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getDemandeAideId()).isEqualTo("demande-123");
      assertThat(dto.getEvaluateurId()).isEqualTo("eval-123");
      assertThat(dto.getEvaluateurNom()).isEqualTo("Évaluateur Test");
      assertThat(dto.getRoleEvaluateur()).isEqualTo("beneficiaire");
      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      assertThat(dto.getNoteGlobale()).isEqualTo(4.5);
      assertThat(dto.getCommentairePrincipal()).isEqualTo("Très satisfait");
      assertThat(dto.getRecommande()).isTrue();
      assertThat(dto.getAideUtile()).isTrue();
      assertThat(dto.getProblemeResolu()).isTrue();
      assertThat(dto.getDateCreation()).isEqualTo(dateCreation);
    }
  }

  @Nested
  @DisplayName("Tests enum TypeEvaluation")
  class TypeEvaluationTests {

    @ParameterizedTest
    @EnumSource(TypeEvaluation.class)
    @DisplayName("TypeEvaluation - toutes les valeurs")
    void testToutesValeurs(TypeEvaluation type) {
      assertThat(type).isNotNull();
      assertThat(type.getLibelle()).isNotNull().isNotEmpty();
    }

    @ParameterizedTest
    @CsvSource({
        "SATISFACTION_BENEFICIAIRE, Satisfaction du bénéficiaire",
        "EVALUATION_PROPOSANT, Évaluation du proposant",
        "EVALUATION_PROCESSUS, Évaluation du processus",
        "SUIVI_POST_AIDE, Suivi post-aide",
        "EVALUATION_IMPACT, Évaluation d'impact",
        "RETOUR_EXPERIENCE, Retour d'expérience"
    })
    @DisplayName("TypeEvaluation - getLibelle")
    void testGetLibelle(TypeEvaluation type, String expected) {
      assertThat(type.getLibelle()).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests enum StatutEvaluation")
  class StatutEvaluationTests {

    @ParameterizedTest
    @EnumSource(StatutEvaluation.class)
    @DisplayName("StatutEvaluation - toutes les valeurs")
    void testToutesValeurs(StatutEvaluation statut) {
      assertThat(statut).isNotNull();
      assertThat(statut.getLibelle()).isNotNull().isNotEmpty();
    }

    @ParameterizedTest
    @CsvSource({
        "BROUILLON, Brouillon",
        "ACTIVE, Active",
        "MASQUEE, Masquée",
        "SIGNALEE, Signalée",
        "SUPPRIMEE, Supprimée"
    })
    @DisplayName("StatutEvaluation - getLibelle")
    void testGetLibelle(StatutEvaluation statut, String expected) {
      assertThat(statut.getLibelle()).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests méthode getNoteMoyenneDetaillees")
  class GetNoteMoyenneDetailleesTests {

    @Test
    @DisplayName("getNoteMoyenneDetaillees - notes détaillées présentes")
    void testGetNoteMoyenneDetailleesAvecNotes() {
      Map<String, Double> notesDetaillees = new HashMap<>();
      notesDetaillees.put("critere1", 4.0);
      notesDetaillees.put("critere2", 5.0);
      notesDetaillees.put("critere3", 3.0);

      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .notesDetaillees(notesDetaillees)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNoteMoyenneDetaillees()).isEqualTo(4.0); // (4.0 + 5.0 + 3.0) / 3 = 4.0
    }

    @Test
    @DisplayName("getNoteMoyenneDetaillees - notes détaillées null")
    void testGetNoteMoyenneDetailleesNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.5)
          .notesDetaillees(null)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNoteMoyenneDetaillees()).isEqualTo(4.5);
    }

    @Test
    @DisplayName("getNoteMoyenneDetaillees - notes détaillées vides")
    void testGetNoteMoyenneDetailleesVides() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(3.5)
          .notesDetaillees(new HashMap<>())
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNoteMoyenneDetaillees()).isEqualTo(3.5);
    }
  }

  @Nested
  @DisplayName("Tests méthode isPositive")
  class IsPositiveTests {

    @ParameterizedTest
    @CsvSource({
        "5.0, true",
        "4.0, true",
        "4.5, true",
        "3.9, false",
        "3.0, false",
        "1.0, false"
    })
    @DisplayName("isPositive - toutes les notes")
    void testIsPositive(Double note, Boolean expected) {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(note)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isPositive()).isEqualTo(expected);
    }

    @Test
    @DisplayName("isPositive - note null")
    void testIsPositiveNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(null)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isPositive()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests méthode isNegative")
  class IsNegativeTests {

    @ParameterizedTest
    @CsvSource({
        "1.0, true",
        "2.0, true",
        "2.5, false",
        "3.0, false",
        "4.0, false",
        "5.0, false"
    })
    @DisplayName("isNegative - toutes les notes")
    void testIsNegative(Double note, Boolean expected) {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(note)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isNegative()).isEqualTo(expected);
    }

    @Test
    @DisplayName("isNegative - note null")
    void testIsNegativeNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(null)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isNegative()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests méthode getScoreQualite")
  class GetScoreQualiteTests {

    @Test
    @DisplayName("getScoreQualite - score de base")
    void testGetScoreQualiteBase() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .dateModification(LocalDateTime.of(2025, 1, 15, 10, 0)) // Date fixe pour éviter les variations
          .recommande(false) // S'assurer que recommande est false pour le score de base
          .problemeResolu(false) // S'assurer que problemeResolu est false pour le score de base
          .nombreSignalements(0) // S'assurer que nombreSignalements est 0
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      // Le score de base est la note globale (4.0)
      assertThat(dto.getScoreQualite()).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - avec notes détaillées")
    void testGetScoreQualiteAvecNotesDetaillees() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .noteDelaiReponse(5.0)
          .noteCommunication(4.5)
          .noteProfessionnalisme(4.0)
          .noteRespectEngagements(5.0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 + (5.0 * 0.1) + (4.5 * 0.1) + (4.0 * 0.1) + (5.0 * 0.1) = 4.0 + 0.5 + 0.45 + 0.4 + 0.5 = 5.85 -> 5.0 (max)
      assertThat(score).isGreaterThanOrEqualTo(4.0);
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("getScoreQualite - avec recommandation et résolution")
    void testGetScoreQualiteAvecBonus() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .recommande(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 + 0.2 + 0.3 = 4.5
      assertThat(score).isGreaterThanOrEqualTo(4.0);
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("getScoreQualite - avec signalements")
    void testGetScoreQualiteAvecSignalements() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .nombreSignalements(2)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 - (2 * 0.1) = 3.8
      assertThat(score).isGreaterThanOrEqualTo(0.0);
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("getScoreQualite - note null")
    void testGetScoreQualiteNoteNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(null)
          .dateModification(LocalDateTime.of(2025, 1, 15, 10, 0)) // Date fixe
          .noteDelaiReponse(null) // S'assurer que les notes détaillées sont null
          .noteCommunication(null)
          .noteProfessionnalisme(null)
          .noteRespectEngagements(null)
          .recommande(null) // S'assurer que recommande est null
          .problemeResolu(null) // S'assurer que problemeResolu est null
          .nombreSignalements(0) // S'assurer que nombreSignalements est 0
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      // Si noteGlobale est null, le score de base est 0.0
      assertThat(dto.getScoreQualite()).isEqualTo(0.0);
    }
  }

  @Nested
  @DisplayName("Tests méthode isComplete")
  class IsCompleteTests {

    @Test
    @DisplayName("isComplete - évaluation complète")
    void testIsCompleteComplet() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("Commentaire valide")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isTrue();
    }

    @Test
    @DisplayName("isComplete - note globale null")
    void testIsCompleteNoteNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(null)
          .commentairePrincipal("Commentaire")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }

    @Test
    @DisplayName("isComplete - commentaire null")
    void testIsCompleteCommentaireNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal(null)
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }

    @Test
    @DisplayName("isComplete - commentaire vide")
    void testIsCompleteCommentaireVide() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("   ")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }

    @Test
    @DisplayName("isComplete - recommande null")
    void testIsCompleteRecommandeNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("Commentaire")
          .recommande(null)
          .aideUtile(true)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }

    @Test
    @DisplayName("isComplete - aideUtile null")
    void testIsCompleteAideUtileNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("Commentaire")
          .recommande(true)
          .aideUtile(null)
          .problemeResolu(true)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }

    @Test
    @DisplayName("isComplete - problemeResolu null")
    void testIsCompleteProblemeResoluNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("Commentaire")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(null)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.isComplete()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests méthode getNiveauSatisfaction")
  class GetNiveauSatisfactionTests {

    @ParameterizedTest
    @CsvSource({
        "5.0, Excellent",
        "4.0, Très bien",
        "3.0, Bien",
        "2.0, Passable",
        "1.0, Insuffisant",
        "4.5, Très bien",
        "3.5, Bien"
    })
    @DisplayName("getNiveauSatisfaction - toutes les notes")
    void testGetNiveauSatisfaction(Double note, String expected) {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(note)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNiveauSatisfaction()).isEqualTo(expected);
    }

    @Test
    @DisplayName("getNiveauSatisfaction - note null")
    void testGetNiveauSatisfactionNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(null)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }

    @Test
    @DisplayName("getNiveauSatisfaction - note hors plage")
    void testGetNiveauSatisfactionHorsPlage() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(6.0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }
  }

  @Nested
  @DisplayName("Tests valeurs par défaut")
  class ValeursParDefautTests {

    @Test
    @DisplayName("typeEvaluation - valeur par défaut")
    void testTypeEvaluationParDefaut() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .build();
      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
    }

    @Test
    @DisplayName("dateCreation - initialisée par défaut")
    void testDateCreationParDefaut() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .build();
      assertThat(dto.getDateCreation()).isNotNull();
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estPublique - toutes les valeurs")
    void testEstPublique(Boolean valeur) {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .estPublique(valeur)
          .build();
      assertThat(dto.getEstPublique()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("recommande - toutes les valeurs")
    void testRecommande(Boolean valeur) {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .recommande(valeur)
          .build();
      assertThat(dto.getRecommande()).isEqualTo(valeur);
    }

    @Test
    @DisplayName("statut - valeur par défaut")
    void testStatutParDefaut() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .build();
      assertThat(dto.getStatut()).isEqualTo(StatutEvaluation.ACTIVE);
    }
  }

  @Nested
  @DisplayName("Tests equals/hashCode/toString")
  class EqualsHashCodeToStringTests {

    @Test
    @DisplayName("equals - même objet")
    void testEqualsMemeObjet() {
      EvaluationAideDTO dto = new EvaluationAideDTO();
      assertThat(dto).isEqualTo(dto);
    }

    @Test
    @DisplayName("equals - objets égaux")
    void testEqualsObjetsEgaux() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      
      EvaluationAideDTO dto1 = EvaluationAideDTO.builder()
          .id("id-1")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();
      EvaluationAideDTO dto2 = EvaluationAideDTO.builder()
          .id("id-1")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();

      assertThat(dto1).isEqualTo(dto2);
      assertThat(dto1.hashCode()).isEqualTo(dto2.hashCode());
    }

    @Test
    @DisplayName("equals - objets différents")
    void testEqualsObjetsDifferent() {
      EvaluationAideDTO dto1 = EvaluationAideDTO.builder()
          .id("id-1")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .build();
      EvaluationAideDTO dto2 = EvaluationAideDTO.builder()
          .id("id-2")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .build();

      assertThat(dto1).isNotEqualTo(dto2);
    }

    @Test
    @DisplayName("equals - avec null")
    void testEqualsAvecNull() {
      EvaluationAideDTO dto = new EvaluationAideDTO();
      assertThat(dto).isNotEqualTo(null);
    }

    @Test
    @DisplayName("hashCode - objets égaux ont même hashCode")
    void testHashCodeObjetsEgaux() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      
      EvaluationAideDTO dto1 = EvaluationAideDTO.builder()
          .id("id-1")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();
      EvaluationAideDTO dto2 = EvaluationAideDTO.builder()
          .id("id-1")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();

      assertThat(dto1.hashCode()).isEqualTo(dto2.hashCode());
    }

    @Test
    @DisplayName("toString - contient les informations essentielles")
    void testToString() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .id("id-123")
          .demandeAideId("demande-123")
          .evaluateurNom("Évaluateur")
          .noteGlobale(4.5)
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("EvaluationAideDTO");
      assertThat(toString).contains("id-123");
    }

    @Test
    @DisplayName("toString - avec tous les champs")
    void testToStringTousChamps() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .id("id-123")
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .evaluateurNom("Évaluateur")
          .roleEvaluateur("beneficiaire")
          .typeEvaluation(TypeEvaluation.SATISFACTION_BENEFICIAIRE)
          .noteGlobale(4.5)
          .commentairePrincipal("Commentaire")
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("EvaluationAideDTO");
      assertThat(toString).contains("id-123");
      assertThat(toString).contains("Évaluateur");
    }
  }

  @Nested
  @DisplayName("Tests getters/setters supplémentaires")
  class GettersSettersSupplementairesTests {

    @Test
    @DisplayName("Test tous les champs manquants")
    void testTousLesChampsManquants() {
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 20, 10, 0);
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(new PieceJustificativeDTO());
      List<String> tags = Arrays.asList("tag1", "tag2");
      Map<String, Object> donnees = new HashMap<>();
      donnees.put("key1", "value1");

      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .noteGlobale(4.0)
          .propositionAideId("prop-123")
          .pointsPositifs("Points positifs")
          .pointsAmelioration("Points d'amélioration")
          .recommandations("Recommandations")
          .noteDelaiReponse(4.5)
          .noteCommunication(4.0)
          .noteProfessionnalisme(5.0)
          .noteRespectEngagements(4.5)
          .dateVerification(dateVerification)
          .verificateurId("verif-123")
          .piecesJointes(piecesJointes)
          .tags(tags)
          .donneesAdditionnelles(donnees)
          .build();

      assertThat(dto.getPropositionAideId()).isEqualTo("prop-123");
      assertThat(dto.getPointsPositifs()).isEqualTo("Points positifs");
      assertThat(dto.getPointsAmelioration()).isEqualTo("Points d'amélioration");
      assertThat(dto.getRecommandations()).isEqualTo("Recommandations");
      assertThat(dto.getNoteDelaiReponse()).isEqualTo(4.5);
      assertThat(dto.getNoteCommunication()).isEqualTo(4.0);
      assertThat(dto.getNoteProfessionnalisme()).isEqualTo(5.0);
      assertThat(dto.getNoteRespectEngagements()).isEqualTo(4.5);
      assertThat(dto.getDateVerification()).isEqualTo(dateVerification);
      assertThat(dto.getVerificateurId()).isEqualTo("verif-123");
      assertThat(dto.getPiecesJointes()).isEqualTo(piecesJointes);
      assertThat(dto.getTags()).isEqualTo(tags);
      assertThat(dto.getDonneesAdditionnelles()).isEqualTo(donnees);
    }

    @Test
    @DisplayName("Test tous les setters directs")
    void testTousLesSettersDirects() {
      EvaluationAideDTO dto = new EvaluationAideDTO();
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 20, 10, 0);
      Map<String, Double> notesDetaillees = new HashMap<>();
      notesDetaillees.put("critere1", 4.0);
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(new PieceJustificativeDTO());
      List<String> tags = Arrays.asList("tag1");
      Map<String, Object> donnees = new HashMap<>();
      donnees.put("key", "value");

      dto.setId("id-test");
      dto.setDemandeAideId("demande-123");
      dto.setPropositionAideId("prop-123");
      dto.setEvaluateurId("eval-123");
      dto.setEvaluateurNom("Évaluateur Test");
      dto.setRoleEvaluateur("beneficiaire");
      dto.setTypeEvaluation(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      dto.setNoteGlobale(4.5);
      dto.setNotesDetaillees(notesDetaillees);
      dto.setCommentairePrincipal("Commentaire principal");
      dto.setPointsPositifs("Points positifs");
      dto.setPointsAmelioration("Points d'amélioration");
      dto.setRecommandations("Recommandations");
      dto.setRecommande(true);
      dto.setAideUtile(true);
      dto.setProblemeResolu(true);
      dto.setNoteDelaiReponse(4.5);
      dto.setNoteCommunication(4.0);
      dto.setNoteProfessionnalisme(5.0);
      dto.setNoteRespectEngagements(4.5);
      dto.setDateCreation(dateCreation);
      dto.setDateModification(dateModification);
      dto.setEstPublique(true);
      dto.setEstAnonyme(false);
      dto.setEstVerifiee(true);
      dto.setDateVerification(dateVerification);
      dto.setVerificateurId("verif-123");
      dto.setPiecesJointes(piecesJointes);
      dto.setTags(tags);
      dto.setDonneesAdditionnelles(donnees);
      dto.setNombreUtile(5);
      dto.setNombreSignalements(0);
      dto.setStatut(StatutEvaluation.ACTIVE);

      assertThat(dto.getId()).isEqualTo("id-test");
      assertThat(dto.getDemandeAideId()).isEqualTo("demande-123");
      assertThat(dto.getPropositionAideId()).isEqualTo("prop-123");
      assertThat(dto.getEvaluateurId()).isEqualTo("eval-123");
      assertThat(dto.getEvaluateurNom()).isEqualTo("Évaluateur Test");
      assertThat(dto.getRoleEvaluateur()).isEqualTo("beneficiaire");
      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      assertThat(dto.getNoteGlobale()).isEqualTo(4.5);
      assertThat(dto.getNotesDetaillees()).isEqualTo(notesDetaillees);
      assertThat(dto.getCommentairePrincipal()).isEqualTo("Commentaire principal");
      assertThat(dto.getPointsPositifs()).isEqualTo("Points positifs");
      assertThat(dto.getPointsAmelioration()).isEqualTo("Points d'amélioration");
      assertThat(dto.getRecommandations()).isEqualTo("Recommandations");
      assertThat(dto.getRecommande()).isTrue();
      assertThat(dto.getAideUtile()).isTrue();
      assertThat(dto.getProblemeResolu()).isTrue();
      assertThat(dto.getNoteDelaiReponse()).isEqualTo(4.5);
      assertThat(dto.getNoteCommunication()).isEqualTo(4.0);
      assertThat(dto.getNoteProfessionnalisme()).isEqualTo(5.0);
      assertThat(dto.getNoteRespectEngagements()).isEqualTo(4.5);
      assertThat(dto.getDateCreation()).isEqualTo(dateCreation);
      assertThat(dto.getDateModification()).isEqualTo(dateModification);
      assertThat(dto.getEstPublique()).isTrue();
      assertThat(dto.getEstAnonyme()).isFalse();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getDateVerification()).isEqualTo(dateVerification);
      assertThat(dto.getVerificateurId()).isEqualTo("verif-123");
      assertThat(dto.getPiecesJointes()).isEqualTo(piecesJointes);
      assertThat(dto.getTags()).isEqualTo(tags);
      assertThat(dto.getDonneesAdditionnelles()).isEqualTo(donnees);
      assertThat(dto.getNombreUtile()).isEqualTo(5);
      assertThat(dto.getNombreSignalements()).isEqualTo(0);
      assertThat(dto.getStatut()).isEqualTo(StatutEvaluation.ACTIVE);
    }
  }

  @Nested
  @DisplayName("Tests getScoreQualite - branches manquantes")
  class GetScoreQualiteBranchesManquantesTests {

    @Test
    @DisplayName("getScoreQualite - toutes les notes détaillées null")
    void testGetScoreQualiteToutesNotesNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .noteDelaiReponse(null)
          .noteCommunication(null)
          .noteProfessionnalisme(null)
          .noteRespectEngagements(null)
          .recommande(false)
          .problemeResolu(false)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getScoreQualite()).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - recommande null")
    void testGetScoreQualiteRecommandeNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .recommande(null)
          .problemeResolu(false)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 (pas de bonus recommande si null)
      assertThat(score).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - problemeResolu null")
    void testGetScoreQualiteProblemeResoluNull() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .recommande(false)
          .problemeResolu(null)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 (pas de bonus problemeResolu si null)
      assertThat(score).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - recommande false (pas null)")
    void testGetScoreQualiteRecommandeFalse() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .recommande(false)
          .problemeResolu(false)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 (pas de bonus si recommande est false)
      assertThat(score).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - problemeResolu false (pas null)")
    void testGetScoreQualiteProblemeResoluFalse() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(4.0)
          .recommande(false)
          .problemeResolu(false)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // 4.0 (pas de bonus si problemeResolu est false)
      assertThat(score).isEqualTo(4.0);
    }

    @Test
    @DisplayName("getScoreQualite - score plafonné à 5.0")
    void testGetScoreQualitePlafonne() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(5.0)
          .noteDelaiReponse(5.0)
          .noteCommunication(5.0)
          .noteProfessionnalisme(5.0)
          .noteRespectEngagements(5.0)
          .recommande(true)
          .problemeResolu(true)
          .nombreSignalements(0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // Le score devrait être plafonné à 5.0
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("getScoreQualite - score plancher à 0.0")
    void testGetScoreQualitePlancher() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(0.0)
          .nombreSignalements(100)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      double score = dto.getScoreQualite();
      // Le score devrait être plancher à 0.0
      assertThat(score).isGreaterThanOrEqualTo(0.0);
    }
  }

  @Nested
  @DisplayName("Tests getNiveauSatisfaction - branches manquantes")
  class GetNiveauSatisfactionBranchesManquantesTests {

    @Test
    @DisplayName("getNiveauSatisfaction - note 0")
    void testGetNiveauSatisfactionNoteZero() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(0.0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }

    @Test
    @DisplayName("getNiveauSatisfaction - note 6 (hors plage)")
    void testGetNiveauSatisfactionNoteHorsPlage() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .noteGlobale(6.0)
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }
  }

  @Nested
  @DisplayName("Tests Builder complet - tous les champs")
  class BuilderCompletTests {

    @Test
    @DisplayName("Builder - tous les champs")
    void testBuilderTousChamps() {
      LocalDateTime now = LocalDateTime.now();
      Map<String, Object> donneesPersonnalisees = new HashMap<>();
      donneesPersonnalisees.put("key", "value");
      List<String> tags = Arrays.asList("tag1", "tag2");

      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .id("eval-123")
          .demandeAideId("demande-123")
          .propositionAideId("proposition-123")
          .evaluateurId("eval-123")
          .evaluateurNom("Évaluateur Test")
          .roleEvaluateur("beneficiaire")
          .typeEvaluation(TypeEvaluation.SATISFACTION_BENEFICIAIRE)
          .statut(StatutEvaluation.ACTIVE)
          .noteGlobale(4.5)
          .noteDelaiReponse(5.0)
          .noteCommunication(4.5)
          .noteProfessionnalisme(4.0)
          .noteRespectEngagements(5.0)
          .commentairePrincipal("Commentaire principal")
          .pointsPositifs("Points positifs")
          .pointsAmelioration("Points négatifs")
          .recommandations("Suggestions")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .dateCreation(now)
          .dateModification(now)
          .estPublique(true)
          .estAnonyme(false)
          .estVerifiee(true)
          .verificateurId("verif-123")
          .dateVerification(now)
          .nombreUtile(10)
          .nombreSignalements(0)
          .donneesAdditionnelles(donneesPersonnalisees)
          .tags(tags)
          .build();

      assertThat(dto.getId()).isEqualTo("eval-123");
      assertThat(dto.getDemandeAideId()).isEqualTo("demande-123");
      assertThat(dto.getPropositionAideId()).isEqualTo("proposition-123");
      assertThat(dto.getEvaluateurId()).isEqualTo("eval-123");
      assertThat(dto.getEvaluateurNom()).isEqualTo("Évaluateur Test");
      assertThat(dto.getRoleEvaluateur()).isEqualTo("beneficiaire");
      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      assertThat(dto.getStatut()).isEqualTo(StatutEvaluation.ACTIVE);
      assertThat(dto.getNoteGlobale()).isEqualTo(4.5);
      assertThat(dto.getNoteDelaiReponse()).isEqualTo(5.0);
      assertThat(dto.getNoteCommunication()).isEqualTo(4.5);
      assertThat(dto.getNoteProfessionnalisme()).isEqualTo(4.0);
      assertThat(dto.getNoteRespectEngagements()).isEqualTo(5.0);
      assertThat(dto.getCommentairePrincipal()).isEqualTo("Commentaire principal");
      assertThat(dto.getPointsPositifs()).isEqualTo("Points positifs");
      assertThat(dto.getPointsAmelioration()).isEqualTo("Points négatifs");
      assertThat(dto.getRecommandations()).isEqualTo("Suggestions");
      assertThat(dto.getRecommande()).isTrue();
      assertThat(dto.getAideUtile()).isTrue();
      assertThat(dto.getProblemeResolu()).isTrue();
      assertThat(dto.getDateCreation()).isEqualTo(now);
      assertThat(dto.getDateModification()).isEqualTo(now);
      assertThat(dto.getEstPublique()).isTrue();
      assertThat(dto.getEstAnonyme()).isFalse();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getVerificateurId()).isEqualTo("verif-123");
      assertThat(dto.getDateVerification()).isEqualTo(now);
      assertThat(dto.getNombreUtile()).isEqualTo(10);
      assertThat(dto.getNombreSignalements()).isEqualTo(0);
      assertThat(dto.getDonneesAdditionnelles()).isEqualTo(donneesPersonnalisees);
      assertThat(dto.getTags()).isEqualTo(tags);
    }

    @Test
    @DisplayName("Builder - valeurs par défaut")
    void testBuilderValeursParDefaut() {
      EvaluationAideDTO dto = EvaluationAideDTO.builder()
          .demandeAideId("demande-123")
          .evaluateurId("eval-123")
          .roleEvaluateur("beneficiaire")
          .build();

      assertThat(dto.getTypeEvaluation()).isEqualTo(TypeEvaluation.SATISFACTION_BENEFICIAIRE);
      assertThat(dto.getDateCreation()).isNotNull();
      assertThat(dto.getDateModification()).isNotNull();
      assertThat(dto.getEstPublique()).isTrue();
      assertThat(dto.getEstAnonyme()).isFalse();
      assertThat(dto.getEstVerifiee()).isFalse();
      assertThat(dto.getRecommande()).isTrue();
      assertThat(dto.getAideUtile()).isTrue();
      assertThat(dto.getProblemeResolu()).isTrue();
      assertThat(dto.getStatut()).isEqualTo(StatutEvaluation.ACTIVE);
      assertThat(dto.getNombreUtile()).isEqualTo(0);
      assertThat(dto.getNombreSignalements()).isEqualTo(0);
    }
  }
}

