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

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 org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

@DisplayName("Tests pour PieceJustificativeDTO")
class PieceJustificativeDTOTest {

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

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

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

      assertThat(dto).isNotNull();
      assertThat(dto.getDateAjout()).isNotNull();
      assertThat(dto.getEstObligatoire()).isFalse();
      assertThat(dto.getEstVerifiee()).isFalse();
    }

    @Test
    @DisplayName("Constructeur avec tous les paramètres")
    void testConstructeurAvecParametres() {
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 15, 11, 0);

      PieceJustificativeDTO dto = new PieceJustificativeDTO(
          "id-123",
          "document.pdf",
          "FACTURE",
          "Facture médicale",
          "https://example.com/document.pdf",
          "application/pdf",
          1024L,
          true,
          true,
          dateAjout,
          dateVerification,
          "verificateur-id",
          "Document vérifié et valide");

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getNomFichier()).isEqualTo("document.pdf");
      assertThat(dto.getTypePiece()).isEqualTo("FACTURE");
      assertThat(dto.getDescription()).isEqualTo("Facture médicale");
      assertThat(dto.getUrlFichier()).isEqualTo("https://example.com/document.pdf");
      assertThat(dto.getTypeMime()).isEqualTo("application/pdf");
      assertThat(dto.getTailleFichier()).isEqualTo(1024L);
      assertThat(dto.getEstObligatoire()).isTrue();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getDateAjout()).isEqualTo(dateAjout);
      assertThat(dto.getDateVerification()).isEqualTo(dateVerification);
      assertThat(dto.getVerificateurId()).isEqualTo("verificateur-id");
      assertThat(dto.getCommentairesVerification()).isEqualTo("Document vérifié et valide");
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .id("id-456")
          .nomFichier("justificatif.jpg")
          .typePiece("JUSTIFICATIF")
          .description("Justificatif de domicile")
          .urlFichier("https://example.com/justificatif.jpg")
          .typeMime("image/jpeg")
          .tailleFichier(2048L)
          .estObligatoire(false)
          .estVerifiee(true)
          .build();

      assertThat(dto.getId()).isEqualTo("id-456");
      assertThat(dto.getNomFichier()).isEqualTo("justificatif.jpg");
      assertThat(dto.getTypePiece()).isEqualTo("JUSTIFICATIF");
      assertThat(dto.getDescription()).isEqualTo("Justificatif de domicile");
      assertThat(dto.getUrlFichier()).isEqualTo("https://example.com/justificatif.jpg");
      assertThat(dto.getTypeMime()).isEqualTo("image/jpeg");
      assertThat(dto.getTailleFichier()).isEqualTo(2048L);
      assertThat(dto.getEstObligatoire()).isFalse();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getDateAjout()).isNotNull();
    }
  }

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

    @Test
    @DisplayName("dateAjout - initialisée par défaut")
    void testDateAjoutParDefaut() {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .build();

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

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estObligatoire - toutes les valeurs")
    void testEstObligatoire(Boolean valeur) {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .estObligatoire(valeur)
          .build();
      assertThat(dto.getEstObligatoire()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estVerifiee - toutes les valeurs")
    void testEstVerifiee(Boolean valeur) {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .estVerifiee(valeur)
          .build();
      assertThat(dto.getEstVerifiee()).isEqualTo(valeur);
    }
  }

  @Nested
  @DisplayName("Tests getters/setters complets")
  class GettersSettersTests {

    @Test
    @DisplayName("Test tous les champs avec setters directs")
    void testTousLesChampsSetters() {
      PieceJustificativeDTO dto = new PieceJustificativeDTO();
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 15, 11, 0);

      dto.setId("id-123");
      dto.setNomFichier("document.pdf");
      dto.setTypePiece("FACTURE");
      dto.setDescription("Facture médicale");
      dto.setUrlFichier("https://example.com/document.pdf");
      dto.setTypeMime("application/pdf");
      dto.setTailleFichier(1024L);
      dto.setEstObligatoire(true);
      dto.setEstVerifiee(true);
      dto.setDateAjout(dateAjout);
      dto.setDateVerification(dateVerification);
      dto.setVerificateurId("verificateur-id");
      dto.setCommentairesVerification("Document vérifié");

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getNomFichier()).isEqualTo("document.pdf");
      assertThat(dto.getTypePiece()).isEqualTo("FACTURE");
      assertThat(dto.getDescription()).isEqualTo("Facture médicale");
      assertThat(dto.getUrlFichier()).isEqualTo("https://example.com/document.pdf");
      assertThat(dto.getTypeMime()).isEqualTo("application/pdf");
      assertThat(dto.getTailleFichier()).isEqualTo(1024L);
      assertThat(dto.getEstObligatoire()).isTrue();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getDateAjout()).isEqualTo(dateAjout);
      assertThat(dto.getDateVerification()).isEqualTo(dateVerification);
      assertThat(dto.getVerificateurId()).isEqualTo("verificateur-id");
      assertThat(dto.getCommentairesVerification()).isEqualTo("Document vérifié");
    }

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

      dto.setId(null);
      dto.setNomFichier(null);
      dto.setTypePiece(null);
      dto.setDescription(null);
      dto.setUrlFichier(null);
      dto.setTypeMime(null);
      dto.setTailleFichier(null);
      dto.setEstObligatoire(null);
      dto.setEstVerifiee(null);
      dto.setDateAjout(null);
      dto.setDateVerification(null);
      dto.setVerificateurId(null);
      dto.setCommentairesVerification(null);

      assertThat(dto.getId()).isNull();
      assertThat(dto.getNomFichier()).isNull();
      assertThat(dto.getTypePiece()).isNull();
      assertThat(dto.getDescription()).isNull();
      assertThat(dto.getUrlFichier()).isNull();
      assertThat(dto.getTypeMime()).isNull();
      assertThat(dto.getTailleFichier()).isNull();
      assertThat(dto.getEstObligatoire()).isNull();
      assertThat(dto.getEstVerifiee()).isNull();
      assertThat(dto.getDateAjout()).isNull();
      assertThat(dto.getDateVerification()).isNull();
      assertThat(dto.getVerificateurId()).isNull();
      assertThat(dto.getCommentairesVerification()).isNull();
    }
  }

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

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

    @Test
    @DisplayName("equals - objets égaux")
    void testEqualsObjetsEgaux() {
      // Utiliser une date fixe pour éviter les différences de dateAjout
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 15, 11, 0);
      PieceJustificativeDTO dto1 = PieceJustificativeDTO.builder()
          .id("id-1")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .description("Description")
          .urlFichier("https://example.com/test.pdf")
          .typeMime("application/pdf")
          .tailleFichier(1024L)
          .estObligatoire(true)
          .estVerifiee(true)
          .dateAjout(dateAjout)
          .dateVerification(dateVerification)
          .verificateurId("verif-id")
          .commentairesVerification("Commentaires")
          .build();
      PieceJustificativeDTO dto2 = PieceJustificativeDTO.builder()
          .id("id-1")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .description("Description")
          .urlFichier("https://example.com/test.pdf")
          .typeMime("application/pdf")
          .tailleFichier(1024L)
          .estObligatoire(true)
          .estVerifiee(true)
          .dateAjout(dateAjout)
          .dateVerification(dateVerification)
          .verificateurId("verif-id")
          .commentairesVerification("Commentaires")
          .build();

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

    @Test
    @DisplayName("equals - objets différents")
    void testEqualsObjetsDifferent() {
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      PieceJustificativeDTO dto1 = PieceJustificativeDTO.builder()
          .id("id-1")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .dateAjout(dateAjout)
          .build();
      PieceJustificativeDTO dto2 = PieceJustificativeDTO.builder()
          .id("id-2")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .dateAjout(dateAjout)
          .build();

      assertThat(dto1).isNotEqualTo(dto2);
    }

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

    @Test
    @DisplayName("hashCode - objets égaux ont même hashCode")
    void testHashCodeObjetsEgaux() {
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      PieceJustificativeDTO dto1 = PieceJustificativeDTO.builder()
          .id("id-1")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .dateAjout(dateAjout)
          .build();
      PieceJustificativeDTO dto2 = PieceJustificativeDTO.builder()
          .id("id-1")
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .dateAjout(dateAjout)
          .build();

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

    @Test
    @DisplayName("toString - contient les informations essentielles")
    void testToString() {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .id("id-123")
          .nomFichier("document.pdf")
          .typePiece("FACTURE")
          .urlFichier("https://example.com/document.pdf")
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("PieceJustificativeDTO");
      assertThat(toString).contains("id-123");
      assertThat(toString).contains("document.pdf");
      assertThat(toString).contains("FACTURE");
    }

    @Test
    @DisplayName("toString - avec tous les champs")
    void testToStringTousChamps() {
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 15, 11, 0);
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .id("id-123")
          .nomFichier("document.pdf")
          .typePiece("FACTURE")
          .description("Facture médicale")
          .urlFichier("https://example.com/document.pdf")
          .typeMime("application/pdf")
          .tailleFichier(1024L)
          .estObligatoire(true)
          .estVerifiee(true)
          .dateAjout(dateAjout)
          .dateVerification(dateVerification)
          .verificateurId("verif-id")
          .commentairesVerification("Document vérifié")
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("PieceJustificativeDTO");
      assertThat(toString).contains("id-123");
      assertThat(toString).contains("document.pdf");
    }
  }

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

    @Test
    @DisplayName("Builder - tous les champs")
    void testBuilderTousChamps() {
      LocalDateTime dateAjout = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime dateVerification = LocalDateTime.of(2025, 1, 15, 11, 0);

      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .id("id-123")
          .nomFichier("document.pdf")
          .typePiece("FACTURE")
          .description("Facture médicale complète")
          .urlFichier("https://example.com/document.pdf")
          .typeMime("application/pdf")
          .tailleFichier(2048L)
          .estObligatoire(true)
          .estVerifiee(true)
          .dateAjout(dateAjout)
          .dateVerification(dateVerification)
          .verificateurId("verif-123")
          .commentairesVerification("Document vérifié et valide")
          .build();

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getNomFichier()).isEqualTo("document.pdf");
      assertThat(dto.getTypePiece()).isEqualTo("FACTURE");
      assertThat(dto.getDescription()).isEqualTo("Facture médicale complète");
      assertThat(dto.getUrlFichier()).isEqualTo("https://example.com/document.pdf");
      assertThat(dto.getTypeMime()).isEqualTo("application/pdf");
      assertThat(dto.getTailleFichier()).isEqualTo(2048L);
      assertThat(dto.getEstObligatoire()).isTrue();
      assertThat(dto.getEstVerifiee()).isTrue();
      assertThat(dto.getDateAjout()).isEqualTo(dateAjout);
      assertThat(dto.getDateVerification()).isEqualTo(dateVerification);
      assertThat(dto.getVerificateurId()).isEqualTo("verif-123");
      assertThat(dto.getCommentairesVerification()).isEqualTo("Document vérifié et valide");
    }

    @Test
    @DisplayName("Builder - valeurs par défaut")
    void testBuilderValeursParDefaut() {
      PieceJustificativeDTO dto = PieceJustificativeDTO.builder()
          .nomFichier("test.pdf")
          .typePiece("TYPE")
          .urlFichier("https://example.com/test.pdf")
          .build();

      assertThat(dto.getDateAjout()).isNotNull();
      assertThat(dto.getEstObligatoire()).isFalse();
      assertThat(dto.getEstVerifiee()).isFalse();
    }
  }
}

