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

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

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 ContactUrgenceDTO")
class ContactUrgenceDTOTest {

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

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

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

      assertThat(dto).isNotNull();
      assertThat(dto.getPeutPrendreDecisions()).isFalse();
      assertThat(dto.getNotificationAutomatique()).isTrue();
    }

    @Test
    @DisplayName("Constructeur avec tous les paramètres")
    void testConstructeurAvecParametres() {
      ContactUrgenceDTO dto = new ContactUrgenceDTO(
          "Jean Dupont",
          "Frère",
          "+221771234567",
          "+221771234568",
          "jean@example.com",
          "123 Rue Test",
          "Toujours disponible",
          false,
          true,
          "Commentaires additionnels");

      assertThat(dto.getNomComplet()).isEqualTo("Jean Dupont");
      assertThat(dto.getRelation()).isEqualTo("Frère");
      assertThat(dto.getTelephonePrincipal()).isEqualTo("+221771234567");
      assertThat(dto.getTelephoneSecondaire()).isEqualTo("+221771234568");
      assertThat(dto.getEmail()).isEqualTo("jean@example.com");
      assertThat(dto.getAdresse()).isEqualTo("123 Rue Test");
      assertThat(dto.getDisponibilite()).isEqualTo("Toujours disponible");
      assertThat(dto.getPeutPrendreDecisions()).isFalse();
      assertThat(dto.getNotificationAutomatique()).isTrue();
      assertThat(dto.getCommentaires()).isEqualTo("Commentaires additionnels");
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
          .nomComplet("Marie Martin")
          .relation("Sœur")
          .telephonePrincipal("+221771234569")
          .email("marie@example.com")
          .adresse("456 Rue Autre")
          .disponibilite("9h-17h")
          .peutPrendreDecisions(true)
          .notificationAutomatique(false)
          .commentaires("Contact préféré")
          .build();

      assertThat(dto.getNomComplet()).isEqualTo("Marie Martin");
      assertThat(dto.getRelation()).isEqualTo("Sœur");
      assertThat(dto.getTelephonePrincipal()).isEqualTo("+221771234569");
      assertThat(dto.getEmail()).isEqualTo("marie@example.com");
      assertThat(dto.getAdresse()).isEqualTo("456 Rue Autre");
      assertThat(dto.getDisponibilite()).isEqualTo("9h-17h");
      assertThat(dto.getPeutPrendreDecisions()).isTrue();
      assertThat(dto.getNotificationAutomatique()).isFalse();
      assertThat(dto.getCommentaires()).isEqualTo("Contact préféré");
    }
  }

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

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("peutPrendreDecisions - toutes les valeurs")
    void testPeutPrendreDecisions(Boolean valeur) {
      ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .peutPrendreDecisions(valeur)
          .build();
      assertThat(dto.getPeutPrendreDecisions()).isEqualTo(valeur);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("notificationAutomatique - toutes les valeurs")
    void testNotificationAutomatique(Boolean valeur) {
      ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .notificationAutomatique(valeur)
          .build();
      assertThat(dto.getNotificationAutomatique()).isEqualTo(valeur);
    }
  }

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

    @Test
    @DisplayName("Test tous les champs avec setters directs")
    void testTousLesChampsSetters() {
      ContactUrgenceDTO dto = new ContactUrgenceDTO();

      dto.setNomComplet("Jean Dupont");
      dto.setRelation("Frère");
      dto.setTelephonePrincipal("+221771234567");
      dto.setTelephoneSecondaire("+221771234568");
      dto.setEmail("jean@example.com");
      dto.setAdresse("123 Rue Test");
      dto.setDisponibilite("Toujours disponible");
      dto.setPeutPrendreDecisions(true);
      dto.setNotificationAutomatique(false);
      dto.setCommentaires("Commentaires additionnels");

      assertThat(dto.getNomComplet()).isEqualTo("Jean Dupont");
      assertThat(dto.getRelation()).isEqualTo("Frère");
      assertThat(dto.getTelephonePrincipal()).isEqualTo("+221771234567");
      assertThat(dto.getTelephoneSecondaire()).isEqualTo("+221771234568");
      assertThat(dto.getEmail()).isEqualTo("jean@example.com");
      assertThat(dto.getAdresse()).isEqualTo("123 Rue Test");
      assertThat(dto.getDisponibilite()).isEqualTo("Toujours disponible");
      assertThat(dto.getPeutPrendreDecisions()).isTrue();
      assertThat(dto.getNotificationAutomatique()).isFalse();
      assertThat(dto.getCommentaires()).isEqualTo("Commentaires additionnels");
    }

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

      dto.setNomComplet(null);
      dto.setRelation(null);
      dto.setTelephonePrincipal(null);
      dto.setTelephoneSecondaire(null);
      dto.setEmail(null);
      dto.setAdresse(null);
      dto.setDisponibilite(null);
      dto.setPeutPrendreDecisions(null);
      dto.setNotificationAutomatique(null);
      dto.setCommentaires(null);

      assertThat(dto.getNomComplet()).isNull();
      assertThat(dto.getRelation()).isNull();
      assertThat(dto.getTelephonePrincipal()).isNull();
      assertThat(dto.getTelephoneSecondaire()).isNull();
      assertThat(dto.getEmail()).isNull();
      assertThat(dto.getAdresse()).isNull();
      assertThat(dto.getDisponibilite()).isNull();
      assertThat(dto.getPeutPrendreDecisions()).isNull();
      assertThat(dto.getNotificationAutomatique()).isNull();
      assertThat(dto.getCommentaires()).isNull();
    }
  }

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

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

    @Test
    @DisplayName("equals - objets égaux")
    void testEqualsObjetsEgaux() {
      ContactUrgenceDTO dto1 = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();
      ContactUrgenceDTO dto2 = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();

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

    @Test
    @DisplayName("equals - objets différents")
    void testEqualsObjetsDifferent() {
      ContactUrgenceDTO dto1 = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();
      ContactUrgenceDTO dto2 = ContactUrgenceDTO.builder()
          .nomComplet("Test2")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();

      assertThat(dto1).isNotEqualTo(dto2);
    }

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

    @Test
    @DisplayName("equals - objets avec tous les champs identiques")
    void testEqualsTousChampsIdentiques() {
      ContactUrgenceDTO dto1 = ContactUrgenceDTO.builder()
          .nomComplet("Jean Dupont")
          .relation("Frère")
          .telephonePrincipal("+221771234567")
          .telephoneSecondaire("+221771234568")
          .email("jean@example.com")
          .adresse("123 Rue Test")
          .disponibilite("Toujours disponible")
          .peutPrendreDecisions(true)
          .notificationAutomatique(false)
          .commentaires("Commentaires")
          .build();

      ContactUrgenceDTO dto2 = ContactUrgenceDTO.builder()
          .nomComplet("Jean Dupont")
          .relation("Frère")
          .telephonePrincipal("+221771234567")
          .telephoneSecondaire("+221771234568")
          .email("jean@example.com")
          .adresse("123 Rue Test")
          .disponibilite("Toujours disponible")
          .peutPrendreDecisions(true)
          .notificationAutomatique(false)
          .commentaires("Commentaires")
          .build();

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

    @Test
    @DisplayName("hashCode - objets égaux ont même hashCode")
    void testHashCodeObjetsEgaux() {
      ContactUrgenceDTO dto1 = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();
      ContactUrgenceDTO dto2 = ContactUrgenceDTO.builder()
          .nomComplet("Test")
          .relation("Test")
          .telephonePrincipal("+221771234567")
          .build();

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

    @Test
    @DisplayName("toString - contient les informations essentielles")
    void testToString() {
      ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
          .nomComplet("Jean Dupont")
          .relation("Frère")
          .telephonePrincipal("+221771234567")
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("ContactUrgenceDTO");
      assertThat(toString).contains("Jean Dupont");
      assertThat(toString).contains("Frère");
    }

    @Test
    @DisplayName("toString - avec tous les champs")
    void testToStringTousChamps() {
      ContactUrgenceDTO dto = ContactUrgenceDTO.builder()
          .nomComplet("Jean Dupont")
          .relation("Frère")
          .telephonePrincipal("+221771234567")
          .telephoneSecondaire("+221771234568")
          .email("jean@example.com")
          .adresse("123 Rue Test")
          .disponibilite("Toujours disponible")
          .peutPrendreDecisions(true)
          .notificationAutomatique(false)
          .commentaires("Commentaires")
          .build();

      String toString = dto.toString();
      assertThat(toString).contains("ContactUrgenceDTO");
      assertThat(toString).contains("Jean Dupont");
      assertThat(toString).contains("Frère");
    }
  }
}

