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

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

import java.util.Map;
import java.util.UUID;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

/**
 * Tests unitaires pour EvaluationAideResponse.
 * Couvre getNoteMoyenneDetaillees, isPositive, isNegative, getScoreQualite,
 * isComplete, getNiveauSatisfaction (tous cas du switch).
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2026-02-21
 */
@DisplayName("Tests EvaluationAideResponse")
class EvaluationAideResponseTest {

  @Nested
  @DisplayName("getNoteMoyenneDetaillees")
  class GetNoteMoyenneDetaillees {

    @Test
    @DisplayName("retourne noteGlobale quand notesDetaillees null")
    void testNotesNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .notesDetaillees(null)
          .build();
      assertThat(r.getNoteMoyenneDetaillees()).isEqualTo(4.0);
    }

    @Test
    @DisplayName("retourne noteGlobale quand notesDetaillees vide")
    void testNotesVide() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(3.5)
          .notesDetaillees(Map.of())
          .build();
      assertThat(r.getNoteMoyenneDetaillees()).isEqualTo(3.5);
    }

    @Test
    @DisplayName("retourne moyenne des notes détaillées")
    void testMoyenne() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(5.0)
          .notesDetaillees(Map.of("a", 3.0, "b", 5.0))
          .build();
      assertThat(r.getNoteMoyenneDetaillees()).isEqualTo(4.0);
    }

    @Test
    @DisplayName("retourne noteGlobale quand notesDetaillees non vide mais noteGlobale null (fallback 0)")
    void testNoteGlobaleNullAvecNotes() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(null)
          .notesDetaillees(Map.of("a", 2.0))
          .build();
      assertThat(r.getNoteMoyenneDetaillees()).isEqualTo(2.0);
    }
  }

  @Nested
  @DisplayName("isPositive")
  class IsPositive {

    @Test
    @DisplayName("retourne false quand noteGlobale null")
    void testNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(null).build();
      assertThat(r.isPositive()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand noteGlobale >= 4")
    void testPositive() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(4.0).build();
      assertThat(r.isPositive()).isTrue();
      r.setNoteGlobale(5.0);
      assertThat(r.isPositive()).isTrue();
    }

    @Test
    @DisplayName("retourne false quand noteGlobale < 4")
    void testNonPositive() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(3.9).build();
      assertThat(r.isPositive()).isFalse();
    }
  }

  @Nested
  @DisplayName("isNegative")
  class IsNegative {

    @Test
    @DisplayName("retourne false quand noteGlobale null")
    void testNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(null).build();
      assertThat(r.isNegative()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand noteGlobale <= 2")
    void testNegative() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(2.0).build();
      assertThat(r.isNegative()).isTrue();
      r.setNoteGlobale(1.0);
      assertThat(r.isNegative()).isTrue();
    }

    @Test
    @DisplayName("retourne false quand noteGlobale > 2")
    void testNonNegative() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(2.1).build();
      assertThat(r.isNegative()).isFalse();
    }
  }

  @Nested
  @DisplayName("getScoreQualite")
  class GetScoreQualite {

    @Test
    @DisplayName("retourne 0 quand noteGlobale null et pas d'autres notes")
    void testNoteGlobaleNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(null).build();
      assertThat(r.getScoreQualite()).isEqualTo(0.0);
    }

    @Test
    @DisplayName("inclut noteGlobale et bonus recommande + problemeResolu")
    void testAvecRecommandeEtResolu() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .recommande(true)
          .problemeResolu(true)
          .build();
      double score = r.getScoreQualite();
      assertThat(score).isGreaterThanOrEqualTo(4.0);
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("inclut notes détaillées (delai, communication, etc.)")
    void testAvecNotesDetaillees() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .noteDelaiReponse(5.0)
          .noteCommunication(4.0)
          .noteProfessionnalisme(5.0)
          .noteRespectEngagements(4.0)
          .build();
      double score = r.getScoreQualite();
      assertThat(score).isGreaterThan(4.0);
      assertThat(score).isLessThanOrEqualTo(5.0);
    }

    @Test
    @DisplayName("décrémente avec nombreSignalements")
    void testAvecSignalements() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .nombreSignalements(2)
          .build();
      double score = r.getScoreQualite();
      assertThat(score).isLessThan(4.0);
    }

    @Test
    @DisplayName("score borné entre 0 et 5")
    void testBorne() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(5.0)
          .noteDelaiReponse(5.0)
          .noteCommunication(5.0)
          .noteProfessionnalisme(5.0)
          .noteRespectEngagements(5.0)
          .recommande(true)
          .problemeResolu(true)
          .build();
      assertThat(r.getScoreQualite()).isLessThanOrEqualTo(5.0);
    }
  }

  @Nested
  @DisplayName("isComplete")
  class IsComplete {

    @Test
    @DisplayName("retourne false quand noteGlobale null")
    void testNoteNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .commentairePrincipal("x")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand commentairePrincipal null")
    void testCommentaireNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand commentairePrincipal vide (trim)")
    void testCommentaireVide() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("   ")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand recommande null")
    void testRecommandeNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("OK")
          .aideUtile(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isFalse();
    }

    @Test
    @DisplayName("retourne false quand aideUtile null")
    void testAideUtileNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("OK")
          .recommande(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isFalse();
    }

    @Test
    @DisplayName("retourne true quand tous les champs requis remplis")
    void testComplete() {
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .noteGlobale(4.0)
          .commentairePrincipal("Très bien")
          .recommande(true)
          .aideUtile(true)
          .problemeResolu(true)
          .build();
      assertThat(r.isComplete()).isTrue();
    }
  }

  @Nested
  @DisplayName("getNiveauSatisfaction")
  class GetNiveauSatisfaction {

    @Test
    @DisplayName("retourne Non évalué quand noteGlobale null")
    void testNull() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(null).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }

    @Test
    @DisplayName("note 5 -> Excellent")
    void test5() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(5.0).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Excellent");
    }

    @Test
    @DisplayName("note 4 -> Très bien")
    void test4() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(4.0).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Très bien");
    }

    @Test
    @DisplayName("note 3 -> Bien")
    void test3() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(3.0).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Bien");
    }

    @Test
    @DisplayName("note 2 -> Passable")
    void test2() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(2.0).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Passable");
    }

    @Test
    @DisplayName("note 1 -> Insuffisant")
    void test1() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(1.0).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Insuffisant");
    }

    @Test
    @DisplayName("autre valeur -> Non évalué")
    void testDefault() {
      EvaluationAideResponse r = EvaluationAideResponse.builder().noteGlobale(0.5).build();
      assertThat(r.getNiveauSatisfaction()).isEqualTo("Non évalué");
    }
  }

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

    @Test
    @DisplayName("builder remplit les champs")
    void testBuilder() {
      UUID id = UUID.randomUUID();
      EvaluationAideResponse r = EvaluationAideResponse.builder()
          .demandeAideId(id)
          .noteGlobale(4.5)
          .commentairePrincipal("Bien")
          .build();
      r.setId(id);
      assertThat(r.getId()).isEqualTo(id);
      assertThat(r.getDemandeAideId()).isEqualTo(id);
      assertThat(r.getNoteGlobale()).isEqualTo(4.5);
      assertThat(r.getCommentairePrincipal()).isEqualTo("Bien");
    }
  }
}
