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

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

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
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.ValueSource;

@DisplayName("Tests pour CommentaireAideDTO")
class CommentaireAideDTOTest {

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

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

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

      assertThat(dto).isNotNull();
      assertThat(dto.getDateCreation()).isNotNull();
      assertThat(dto.getEstPrive()).isFalse();
      assertThat(dto.getEstImportant()).isFalse();
      assertThat(dto.getEstModifie()).isFalse();
      assertThat(dto.getNombreReactions()).isEqualTo(0);
      assertThat(dto.getEstResolu()).isFalse();
    }

    @Test
    @DisplayName("Constructeur avec tous les paramètres")
    void testConstructeurAvecParametres() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 15, 11, 0);
      LocalDateTime dateResolution = LocalDateTime.of(2025, 1, 15, 12, 0);
      List<CommentaireAideDTO> reponses = Arrays.asList(new CommentaireAideDTO());
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(new PieceJustificativeDTO());
      List<String> mentions = Arrays.asList("user1", "user2");

      CommentaireAideDTO dto = new CommentaireAideDTO(
          "id-123",
          "Contenu du commentaire",
          "QUESTION",
          dateCreation,
          dateModification,
          "auteur-id",
          "Auteur Nom",
          "ADMIN",
          true,
          true,
          "parent-id",
          reponses,
          piecesJointes,
          mentions,
          true,
          5,
          true,
          dateResolution,
          "resoluteur-id");

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getContenu()).isEqualTo("Contenu du commentaire");
      assertThat(dto.getTypeCommentaire()).isEqualTo("QUESTION");
      assertThat(dto.getDateCreation()).isEqualTo(dateCreation);
      assertThat(dto.getDateModification()).isEqualTo(dateModification);
      assertThat(dto.getAuteurId()).isEqualTo("auteur-id");
      assertThat(dto.getAuteurNom()).isEqualTo("Auteur Nom");
      assertThat(dto.getAuteurRole()).isEqualTo("ADMIN");
      assertThat(dto.getEstPrive()).isTrue();
      assertThat(dto.getEstImportant()).isTrue();
      assertThat(dto.getCommentaireParentId()).isEqualTo("parent-id");
      assertThat(dto.getReponses()).isEqualTo(reponses);
      assertThat(dto.getPiecesJointes()).isEqualTo(piecesJointes);
      assertThat(dto.getMentionsUtilisateurs()).isEqualTo(mentions);
      assertThat(dto.getEstModifie()).isTrue();
      assertThat(dto.getNombreReactions()).isEqualTo(5);
      assertThat(dto.getEstResolu()).isTrue();
      assertThat(dto.getDateResolution()).isEqualTo(dateResolution);
      assertThat(dto.getResoluteurId()).isEqualTo("resoluteur-id");
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .id("id-456")
          .contenu("Contenu test")
          .typeCommentaire("COMMENTAIRE")
          .dateCreation(dateCreation)
          .auteurId("auteur-456")
          .auteurNom("Test Auteur")
          .auteurRole("MEMBRE")
          .estPrive(false)
          .estImportant(true)
          .estModifie(false)
          .nombreReactions(3)
          .estResolu(false)
          .build();

      assertThat(dto.getId()).isEqualTo("id-456");
      assertThat(dto.getContenu()).isEqualTo("Contenu test");
      assertThat(dto.getTypeCommentaire()).isEqualTo("COMMENTAIRE");
      assertThat(dto.getDateCreation()).isEqualTo(dateCreation);
      assertThat(dto.getAuteurId()).isEqualTo("auteur-456");
      assertThat(dto.getAuteurNom()).isEqualTo("Test Auteur");
      assertThat(dto.getAuteurRole()).isEqualTo("MEMBRE");
      assertThat(dto.getEstPrive()).isFalse();
      assertThat(dto.getEstImportant()).isTrue();
      assertThat(dto.getEstModifie()).isFalse();
      assertThat(dto.getNombreReactions()).isEqualTo(3);
      assertThat(dto.getEstResolu()).isFalse();
    }
  }

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

    @Test
    @DisplayName("dateCreation - initialisée par défaut")
    void testDateCreationParDefaut() {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .build();

      assertThat(dto.getDateCreation()).isNotNull();
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estPrive - toutes les valeurs")
    void testEstPrive(Boolean valeur) {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .estPrive(valeur)
          .build();
      assertThat(dto.getEstPrive()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estImportant - toutes les valeurs")
    void testEstImportant(Boolean valeur) {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .estImportant(valeur)
          .build();
      assertThat(dto.getEstImportant()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estModifie - toutes les valeurs")
    void testEstModifie(Boolean valeur) {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .estModifie(valeur)
          .build();
      assertThat(dto.getEstModifie()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estResolu - toutes les valeurs")
    void testEstResolu(Boolean valeur) {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .estResolu(valeur)
          .build();
      assertThat(dto.getEstResolu()).isEqualTo(valeur);
    }

    @Test
    @DisplayName("nombreReactions - valeur par défaut")
    void testNombreReactionsParDefaut() {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .build();
      assertThat(dto.getNombreReactions()).isEqualTo(0);
    }
  }

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

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

    @Test
    @DisplayName("equals - objets égaux")
    void testEqualsObjetsEgaux() {
      // Utiliser une date fixe pour éviter les différences de timestamp
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      
      CommentaireAideDTO dto1 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .dateCreation(dateCreation)
          .build();
      CommentaireAideDTO dto2 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .dateCreation(dateCreation)
          .build();

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

    @Test
    @DisplayName("toString - contient les informations essentielles")
    void testToString() {
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .id("id-123")
          .contenu("Commentaire test")
          .auteurNom("Auteur")
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("CommentaireAideDTO");
      assertThat(toString).contains("id-123");
      assertThat(toString).contains("Commentaire test");
    }
  }

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

    @Test
    @DisplayName("Test tous les champs manquants")
    void testTousLesChampsManquants() {
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      LocalDateTime dateResolution = LocalDateTime.of(2025, 1, 17, 12, 0);
      List<CommentaireAideDTO> reponses = Arrays.asList(new CommentaireAideDTO());
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(new PieceJustificativeDTO());
      List<String> mentions = Arrays.asList("user1", "user2");

      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .contenu("Test")
          .typeCommentaire("TYPE")
          .auteurId("auteur")
          .auteurNom("Auteur Nom")
          .auteurRole("ADMIN")
          .dateModification(dateModification)
          .commentaireParentId("parent-123")
          .reponses(reponses)
          .piecesJointes(piecesJointes)
          .mentionsUtilisateurs(mentions)
          .dateResolution(dateResolution)
          .resoluteurId("resoluteur-123")
          .build();

      assertThat(dto.getAuteurNom()).isEqualTo("Auteur Nom");
      assertThat(dto.getAuteurRole()).isEqualTo("ADMIN");
      assertThat(dto.getDateModification()).isEqualTo(dateModification);
      assertThat(dto.getCommentaireParentId()).isEqualTo("parent-123");
      assertThat(dto.getReponses()).isEqualTo(reponses);
      assertThat(dto.getPiecesJointes()).isEqualTo(piecesJointes);
      assertThat(dto.getMentionsUtilisateurs()).isEqualTo(mentions);
      assertThat(dto.getDateResolution()).isEqualTo(dateResolution);
      assertThat(dto.getResoluteurId()).isEqualTo("resoluteur-123");
    }

    @Test
    @DisplayName("Test setters pour tous les champs")
    void testSetters() {
      CommentaireAideDTO dto = new CommentaireAideDTO();
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 16, 11, 0);
      LocalDateTime dateResolution = LocalDateTime.of(2025, 1, 17, 12, 0);
      List<CommentaireAideDTO> reponses = Arrays.asList(new CommentaireAideDTO());
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(new PieceJustificativeDTO());
      List<String> mentions = Arrays.asList("user1");

      dto.setId("id-test");
      dto.setContenu("Contenu test");
      dto.setTypeCommentaire("TYPE");
      dto.setAuteurId("auteur-id");
      dto.setAuteurNom("Auteur Nom");
      dto.setAuteurRole("ROLE");
      dto.setDateModification(dateModification);
      dto.setCommentaireParentId("parent-id");
      dto.setReponses(reponses);
      dto.setPiecesJointes(piecesJointes);
      dto.setMentionsUtilisateurs(mentions);
      dto.setDateResolution(dateResolution);
      dto.setResoluteurId("resoluteur-id");

      assertThat(dto.getId()).isEqualTo("id-test");
      assertThat(dto.getContenu()).isEqualTo("Contenu test");
      assertThat(dto.getTypeCommentaire()).isEqualTo("TYPE");
      assertThat(dto.getAuteurId()).isEqualTo("auteur-id");
      assertThat(dto.getAuteurNom()).isEqualTo("Auteur Nom");
      assertThat(dto.getAuteurRole()).isEqualTo("ROLE");
      assertThat(dto.getDateModification()).isEqualTo(dateModification);
      assertThat(dto.getCommentaireParentId()).isEqualTo("parent-id");
      assertThat(dto.getReponses()).isEqualTo(reponses);
      assertThat(dto.getPiecesJointes()).isEqualTo(piecesJointes);
      assertThat(dto.getMentionsUtilisateurs()).isEqualTo(mentions);
      assertThat(dto.getDateResolution()).isEqualTo(dateResolution);
      assertThat(dto.getResoluteurId()).isEqualTo("resoluteur-id");
    }

    @Test
    @DisplayName("Test champs null")
    void testChampsNull() {
      CommentaireAideDTO dto = new CommentaireAideDTO();

      dto.setId(null);
      dto.setContenu(null);
      dto.setTypeCommentaire(null);
      dto.setAuteurId(null);
      dto.setAuteurNom(null);
      dto.setAuteurRole(null);
      dto.setDateCreation(null);
      dto.setDateModification(null);
      dto.setCommentaireParentId(null);
      dto.setReponses(null);
      dto.setPiecesJointes(null);
      dto.setMentionsUtilisateurs(null);
      dto.setDateResolution(null);
      dto.setResoluteurId(null);

      assertThat(dto.getId()).isNull();
      assertThat(dto.getContenu()).isNull();
      assertThat(dto.getTypeCommentaire()).isNull();
      assertThat(dto.getAuteurId()).isNull();
      assertThat(dto.getAuteurNom()).isNull();
      assertThat(dto.getAuteurRole()).isNull();
      assertThat(dto.getDateCreation()).isNull();
      assertThat(dto.getDateModification()).isNull();
      assertThat(dto.getCommentaireParentId()).isNull();
      assertThat(dto.getReponses()).isNull();
      assertThat(dto.getPiecesJointes()).isNull();
      assertThat(dto.getMentionsUtilisateurs()).isNull();
      assertThat(dto.getDateResolution()).isNull();
      assertThat(dto.getResoluteurId()).isNull();
    }
  }

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

    @Test
    @DisplayName("equals - objets avec tous les champs identiques")
    void testEqualsTousChampsIdentiques() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 15, 11, 0);
      LocalDateTime dateResolution = LocalDateTime.of(2025, 1, 15, 12, 0);
      LocalDateTime dateAjoutPiece = LocalDateTime.of(2025, 1, 15, 9, 0);
      
      // Créer les objets avec des dates fixes pour éviter les différences
      CommentaireAideDTO reponse = CommentaireAideDTO.builder()
          .dateCreation(dateCreation)
          .build();
      PieceJustificativeDTO piece = PieceJustificativeDTO.builder()
          .dateAjout(dateAjoutPiece)
          .build();
      
      List<CommentaireAideDTO> reponses = Arrays.asList(reponse);
      List<PieceJustificativeDTO> piecesJointes = Arrays.asList(piece);
      List<String> mentions = Arrays.asList("user1");

      CommentaireAideDTO dto1 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Contenu test")
          .typeCommentaire("TYPE")
          .auteurId("auteur-id")
          .auteurNom("Auteur Nom")
          .auteurRole("ROLE")
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .commentaireParentId("parent-id")
          .reponses(reponses)
          .piecesJointes(piecesJointes)
          .mentionsUtilisateurs(mentions)
          .dateResolution(dateResolution)
          .resoluteurId("resoluteur-id")
          .build();

      // Utiliser les mêmes instances pour garantir l'égalité
      CommentaireAideDTO reponse2 = CommentaireAideDTO.builder()
          .dateCreation(dateCreation)
          .build();
      PieceJustificativeDTO piece2 = PieceJustificativeDTO.builder()
          .dateAjout(dateAjoutPiece)
          .build();
      
      List<CommentaireAideDTO> reponses2 = Arrays.asList(reponse2);
      List<PieceJustificativeDTO> piecesJointes2 = Arrays.asList(piece2);
      List<String> mentions2 = Arrays.asList("user1");

      CommentaireAideDTO dto2 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Contenu test")
          .typeCommentaire("TYPE")
          .auteurId("auteur-id")
          .auteurNom("Auteur Nom")
          .auteurRole("ROLE")
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .commentaireParentId("parent-id")
          .reponses(reponses2)
          .piecesJointes(piecesJointes2)
          .mentionsUtilisateurs(mentions2)
          .dateResolution(dateResolution)
          .resoluteurId("resoluteur-id")
          .build();

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

    @Test
    @DisplayName("equals - objets différents")
    void testEqualsObjetsDifferent() {
      CommentaireAideDTO dto1 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Contenu test")
          .build();
      CommentaireAideDTO dto2 = CommentaireAideDTO.builder()
          .id("id-2")
          .contenu("Contenu test")
          .build();

      assertThat(dto1).isNotEqualTo(dto2);
    }

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

    @Test
    @DisplayName("hashCode - objets égaux ont même hashCode")
    void testHashCodeObjetsEgaux() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      CommentaireAideDTO dto1 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Contenu test")
          .dateCreation(dateCreation)
          .build();
      CommentaireAideDTO dto2 = CommentaireAideDTO.builder()
          .id("id-1")
          .contenu("Contenu test")
          .dateCreation(dateCreation)
          .build();

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

    @Test
    @DisplayName("toString - avec tous les champs")
    void testToStringTousChamps() {
      LocalDateTime dateCreation = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateModification = LocalDateTime.of(2025, 1, 15, 11, 0);
      CommentaireAideDTO dto = CommentaireAideDTO.builder()
          .id("id-123")
          .contenu("Contenu test")
          .typeCommentaire("TYPE")
          .auteurId("auteur-id")
          .auteurNom("Auteur Nom")
          .auteurRole("ROLE")
          .dateCreation(dateCreation)
          .dateModification(dateModification)
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("CommentaireAideDTO");
      assertThat(toString).contains("id-123");
      assertThat(toString).contains("Auteur Nom");
    }
  }
}

