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

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

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
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 CreneauDisponibiliteDTO")
class CreneauDisponibiliteDTOTest {

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

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

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

      assertThat(dto).isNotNull();
      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT);
      assertThat(dto.getEstActif()).isTrue();
      assertThat(dto.getFuseauHoraire()).isEqualTo("Africa/Abidjan");
      assertThat(dto.getPriorite()).isEqualTo(3);
    }

    @Test
    @DisplayName("Constructeur avec tous les paramètres")
    void testConstructeurAvecParametres() {
      LocalTime heureDebut = LocalTime.of(9, 0);
      LocalTime heureFin = LocalTime.of(17, 0);
      LocalDate dateSpecifique = LocalDate.of(2025, 1, 20);

      CreneauDisponibiliteDTO dto = new CreneauDisponibiliteDTO(
          "id-123",
          DayOfWeek.MONDAY,
          dateSpecifique,
          heureDebut,
          heureFin,
          CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL,
          false,
          "Europe/Paris",
          "Commentaires",
          2,
          120,
          true,
          15);

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getJourSemaine()).isEqualTo(DayOfWeek.MONDAY);
      assertThat(dto.getDateSpecifique()).isEqualTo(dateSpecifique);
      assertThat(dto.getHeureDebut()).isEqualTo(heureDebut);
      assertThat(dto.getHeureFin()).isEqualTo(heureFin);
      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL);
      assertThat(dto.getEstActif()).isFalse();
      assertThat(dto.getFuseauHoraire()).isEqualTo("Europe/Paris");
      assertThat(dto.getCommentaires()).isEqualTo("Commentaires");
      assertThat(dto.getPriorite()).isEqualTo(2);
      assertThat(dto.getDureeMaxMinutes()).isEqualTo(120);
      assertThat(dto.getPausesNecessaires()).isTrue();
      assertThat(dto.getDureePauseMinutes()).isEqualTo(15);
    }

    @Test
    @DisplayName("Builder pattern")
    void testBuilder() {
      LocalTime heureDebut = LocalTime.of(10, 0);
      LocalTime heureFin = LocalTime.of(12, 0);

      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .id("id-456")
          .jourSemaine(DayOfWeek.TUESDAY)
          .heureDebut(heureDebut)
          .heureFin(heureFin)
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .estActif(true)
          .priorite(1)
          .build();

      assertThat(dto.getId()).isEqualTo("id-456");
      assertThat(dto.getJourSemaine()).isEqualTo(DayOfWeek.TUESDAY);
      assertThat(dto.getHeureDebut()).isEqualTo(heureDebut);
      assertThat(dto.getHeureFin()).isEqualTo(heureFin);
      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT);
      assertThat(dto.getEstActif()).isTrue();
      assertThat(dto.getPriorite()).isEqualTo(1);
    }
  }

  @Nested
  @DisplayName("Tests enum TypeCreneau")
  class TypeCreneauTests {

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

    @ParameterizedTest
    @CsvSource({
        "RECURRENT, Récurrent",
        "PONCTUEL, Ponctuel",
        "URGENCE, Urgence",
        "FLEXIBLE, Flexible"
    })
    @DisplayName("TypeCreneau - getLibelle")
    void testGetLibelle(CreneauDisponibiliteDTO.TypeCreneau type, String expected) {
      assertThat(type.getLibelle()).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests méthode isValide")
  class IsValideTests {

    @Test
    @DisplayName("isValide - créneau valide")
    void testIsValideValide() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

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

    @Test
    @DisplayName("isValide - heure fin avant heure début")
    void testIsValideInvalide() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(17, 0))
          .heureFin(LocalTime.of(9, 0))
          .build();

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

    @Test
    @DisplayName("isValide - heure début null")
    void testIsValideHeureDebutNull() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureFin(LocalTime.of(17, 0))
          .build();

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

    @Test
    @DisplayName("isValide - heure fin null")
    void testIsValideHeureFinNull() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .build();

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

  @Nested
  @DisplayName("Tests méthode getDureeMinutes")
  class GetDureeMinutesTests {

    @Test
    @DisplayName("getDureeMinutes - créneau valide")
    void testGetDureeMinutesValide() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.getDureeMinutes()).isEqualTo(480L); // 8 heures
    }

    @Test
    @DisplayName("getDureeMinutes - créneau invalide")
    void testGetDureeMinutesInvalide() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(17, 0))
          .heureFin(LocalTime.of(9, 0))
          .build();

      assertThat(dto.getDureeMinutes()).isEqualTo(0L);
    }

    @Test
    @DisplayName("getDureeMinutes - 2 heures")
    void testGetDureeMinutes2Heures() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(10, 0))
          .heureFin(LocalTime.of(12, 0))
          .build();

      assertThat(dto.getDureeMinutes()).isEqualTo(120L);
    }
  }

  @Nested
  @DisplayName("Tests méthode isDisponibleLe")
  class IsDisponibleLeTests {

    @Test
    @DisplayName("isDisponibleLe - créneau inactif")
    void testIsDisponibleLeInactif() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(false)
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .build();

      assertThat(dto.isDisponibleLe(LocalDate.of(2025, 1, 20))).isFalse();
    }

    @Test
    @DisplayName("isDisponibleLe - PONCTUEL - date correspond")
    void testIsDisponibleLePonctuelCorrespond() {
      LocalDate date = LocalDate.of(2025, 1, 20);
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(true)
          .type(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL)
          .dateSpecifique(date)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.isDisponibleLe(date)).isTrue();
    }

    @Test
    @DisplayName("isDisponibleLe - PONCTUEL - date ne correspond pas")
    void testIsDisponibleLePonctuelNeCorrespondPas() {
      LocalDate date = LocalDate.of(2025, 1, 20);
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(true)
          .type(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL)
          .dateSpecifique(date)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.isDisponibleLe(LocalDate.of(2025, 1, 21))).isFalse();
    }

    @Test
    @DisplayName("isDisponibleLe - RECURRENT - jour correspond")
    void testIsDisponibleLeRecurrentCorrespond() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(true)
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .jourSemaine(DayOfWeek.MONDAY)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      // 2025-01-20 est un lundi
      assertThat(dto.isDisponibleLe(LocalDate.of(2025, 1, 20))).isTrue();
    }

    @Test
    @DisplayName("isDisponibleLe - RECURRENT - jour ne correspond pas")
    void testIsDisponibleLeRecurrentNeCorrespondPas() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(true)
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .jourSemaine(DayOfWeek.MONDAY)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      // 2025-01-21 est un mardi
      assertThat(dto.isDisponibleLe(LocalDate.of(2025, 1, 21))).isFalse();
    }

    @ParameterizedTest
    @CsvSource({
        "URGENCE, true",
        "FLEXIBLE, true"
    })
    @DisplayName("isDisponibleLe - URGENCE et FLEXIBLE toujours disponibles")
    void testIsDisponibleLeUrgenceFlexible(CreneauDisponibiliteDTO.TypeCreneau type, Boolean expected) {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .estActif(true)
          .type(type)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.isDisponibleLe(LocalDate.of(2025, 1, 20))).isEqualTo(expected);
    }
  }

  @Nested
  @DisplayName("Tests méthode contientHeure")
  class ContientHeureTests {

    @Test
    @DisplayName("contientHeure - heure dans le créneau")
    void testContientHeureDansCreneau() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.contientHeure(LocalTime.of(12, 0))).isTrue();
      assertThat(dto.contientHeure(LocalTime.of(9, 0))).isTrue(); // Limite début
      assertThat(dto.contientHeure(LocalTime.of(17, 0))).isTrue(); // Limite fin
    }

    @Test
    @DisplayName("contientHeure - heure avant le créneau")
    void testContientHeureAvant() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.contientHeure(LocalTime.of(8, 59))).isFalse();
    }

    @Test
    @DisplayName("contientHeure - heure après le créneau")
    void testContientHeureApres() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.contientHeure(LocalTime.of(17, 1))).isFalse();
    }

    @Test
    @DisplayName("contientHeure - créneau invalide")
    void testContientHeureCreneauInvalide() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(17, 0))
          .heureFin(LocalTime.of(9, 0))
          .build();

      assertThat(dto.contientHeure(LocalTime.of(12, 0))).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests méthode getLibelle")
  class GetLibelleTests {

    @Test
    @DisplayName("getLibelle - RECURRENT avec jour")
    void testGetLibelleRecurrent() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .jourSemaine(DayOfWeek.MONDAY)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      String libelle = dto.getLibelle();
      assertThat(libelle).contains("MONDAY");
      assertThat(libelle).contains("09:00");
      assertThat(libelle).contains("17:00");
    }

    @Test
    @DisplayName("getLibelle - PONCTUEL avec date")
    void testGetLibellePonctuel() {
      LocalDate date = LocalDate.of(2025, 1, 20);
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .type(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL)
          .dateSpecifique(date)
          .heureDebut(LocalTime.of(10, 0))
          .heureFin(LocalTime.of(12, 0))
          .build();

      String libelle = dto.getLibelle();
      assertThat(libelle).contains("2025-01-20");
      assertThat(libelle).contains("10:00");
      assertThat(libelle).contains("12:00");
    }

    @Test
    @DisplayName("getLibelle - sans jour ni date")
    void testGetLibelleSansJourNiDate() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .type(CreneauDisponibiliteDTO.TypeCreneau.FLEXIBLE)
          .heureDebut(LocalTime.of(14, 0))
          .heureFin(LocalTime.of(16, 0))
          .build();

      String libelle = dto.getLibelle();
      assertThat(libelle).contains("14:00");
      assertThat(libelle).contains("16:00");
    }
  }

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

    @Test
    @DisplayName("type - valeur par défaut")
    void testTypeParDefaut() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();
      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("estActif - toutes les valeurs")
    void testEstActif(Boolean valeur) {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .estActif(valeur)
          .build();
      assertThat(dto.getEstActif()).isEqualTo(valeur);
    }

    @Test
    @DisplayName("fuseauHoraire - valeur par défaut")
    void testFuseauHoraireParDefaut() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();
      assertThat(dto.getFuseauHoraire()).isEqualTo("Africa/Abidjan");
    }

    @Test
    @DisplayName("priorite - valeur par défaut")
    void testPrioriteParDefaut() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();
      assertThat(dto.getPriorite()).isEqualTo(3);
    }

    @ParameterizedTest
    @ValueSource(booleans = {true, false})
    @DisplayName("pausesNecessaires - toutes les valeurs")
    void testPausesNecessaires(Boolean valeur) {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .pausesNecessaires(valeur)
          .build();
      assertThat(dto.getPausesNecessaires()).isEqualTo(valeur);
    }
  }

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

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

      dto.setId(null);
      dto.setJourSemaine(null);
      dto.setDateSpecifique(null);
      dto.setHeureDebut(null);
      dto.setHeureFin(null);
      dto.setType(null);
      dto.setEstActif(null);
      dto.setFuseauHoraire(null);
      dto.setCommentaires(null);
      dto.setPriorite(null);
      dto.setDureeMaxMinutes(null);
      dto.setPausesNecessaires(null);
      dto.setDureePauseMinutes(null);

      assertThat(dto.getId()).isNull();
      assertThat(dto.getJourSemaine()).isNull();
      assertThat(dto.getDateSpecifique()).isNull();
      assertThat(dto.getHeureDebut()).isNull();
      assertThat(dto.getHeureFin()).isNull();
      assertThat(dto.getType()).isNull();
      assertThat(dto.getEstActif()).isNull();
      assertThat(dto.getFuseauHoraire()).isNull();
      assertThat(dto.getCommentaires()).isNull();
      assertThat(dto.getPriorite()).isNull();
      assertThat(dto.getDureeMaxMinutes()).isNull();
      assertThat(dto.getPausesNecessaires()).isNull();
      assertThat(dto.getDureePauseMinutes()).isNull();
    }
  }

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

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

    @Test
    @DisplayName("equals - objets égaux")
    void testEqualsObjetsEgaux() {
      LocalDate dateSpecifique = LocalDate.of(2025, 1, 15);
      CreneauDisponibiliteDTO dto1 = CreneauDisponibiliteDTO.builder()
          .id("id-1")
          .jourSemaine(DayOfWeek.MONDAY)
          .dateSpecifique(dateSpecifique)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .estActif(true)
          .fuseauHoraire("Africa/Abidjan")
          .commentaires("Commentaires")
          .priorite(5)
          .dureeMaxMinutes(480)
          .pausesNecessaires(true)
          .dureePauseMinutes(15)
          .build();
      CreneauDisponibiliteDTO dto2 = CreneauDisponibiliteDTO.builder()
          .id("id-1")
          .jourSemaine(DayOfWeek.MONDAY)
          .dateSpecifique(dateSpecifique)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .estActif(true)
          .fuseauHoraire("Africa/Abidjan")
          .commentaires("Commentaires")
          .priorite(5)
          .dureeMaxMinutes(480)
          .pausesNecessaires(true)
          .dureePauseMinutes(15)
          .build();

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

    @Test
    @DisplayName("equals - objets différents")
    void testEqualsObjetsDifferent() {
      CreneauDisponibiliteDTO dto1 = CreneauDisponibiliteDTO.builder()
          .id("id-1")
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();
      CreneauDisponibiliteDTO dto2 = CreneauDisponibiliteDTO.builder()
          .id("id-2")
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto1).isNotEqualTo(dto2);
    }

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

    @Test
    @DisplayName("hashCode - objets égaux ont même hashCode")
    void testHashCodeObjetsEgaux() {
      CreneauDisponibiliteDTO dto1 = CreneauDisponibiliteDTO.builder()
          .id("id-1")
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();
      CreneauDisponibiliteDTO dto2 = CreneauDisponibiliteDTO.builder()
          .id("id-1")
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

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

    @Test
    @DisplayName("toString - contient les informations essentielles")
    void testToString() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .id("id-123")
          .jourSemaine(DayOfWeek.MONDAY)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

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

    @Test
    @DisplayName("toString - avec tous les champs")
    void testToStringTousChamps() {
      LocalDate dateSpecifique = LocalDate.of(2025, 1, 15);
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .id("id-123")
          .jourSemaine(DayOfWeek.MONDAY)
          .dateSpecifique(dateSpecifique)
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .type(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT)
          .estActif(true)
          .fuseauHoraire("Africa/Abidjan")
          .commentaires("Commentaires")
          .priorite(5)
          .dureeMaxMinutes(480)
          .pausesNecessaires(true)
          .dureePauseMinutes(15)
          .build();

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

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

    @Test
    @DisplayName("Builder - tous les champs")
    void testBuilderTousChamps() {
      LocalDate dateSpecifique = LocalDate.of(2025, 1, 20);
      LocalTime heureDebut = LocalTime.of(9, 0);
      LocalTime heureFin = LocalTime.of(17, 0);

      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .id("id-123")
          .jourSemaine(DayOfWeek.MONDAY)
          .dateSpecifique(dateSpecifique)
          .heureDebut(heureDebut)
          .heureFin(heureFin)
          .type(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL)
          .estActif(true)
          .fuseauHoraire("Europe/Paris")
          .commentaires("Commentaires complets")
          .priorite(5)
          .dureeMaxMinutes(480)
          .pausesNecessaires(true)
          .dureePauseMinutes(15)
          .build();

      assertThat(dto.getId()).isEqualTo("id-123");
      assertThat(dto.getJourSemaine()).isEqualTo(DayOfWeek.MONDAY);
      assertThat(dto.getDateSpecifique()).isEqualTo(dateSpecifique);
      assertThat(dto.getHeureDebut()).isEqualTo(heureDebut);
      assertThat(dto.getHeureFin()).isEqualTo(heureFin);
      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.PONCTUEL);
      assertThat(dto.getEstActif()).isTrue();
      assertThat(dto.getFuseauHoraire()).isEqualTo("Europe/Paris");
      assertThat(dto.getCommentaires()).isEqualTo("Commentaires complets");
      assertThat(dto.getPriorite()).isEqualTo(5);
      assertThat(dto.getDureeMaxMinutes()).isEqualTo(480);
      assertThat(dto.getPausesNecessaires()).isTrue();
      assertThat(dto.getDureePauseMinutes()).isEqualTo(15);
    }

    @Test
    @DisplayName("Builder - valeurs par défaut")
    void testBuilderValeursParDefaut() {
      CreneauDisponibiliteDTO dto = CreneauDisponibiliteDTO.builder()
          .heureDebut(LocalTime.of(9, 0))
          .heureFin(LocalTime.of(17, 0))
          .build();

      assertThat(dto.getType()).isEqualTo(CreneauDisponibiliteDTO.TypeCreneau.RECURRENT);
      assertThat(dto.getEstActif()).isTrue();
      assertThat(dto.getFuseauHoraire()).isEqualTo("Africa/Abidjan");
      assertThat(dto.getPriorite()).isEqualTo(3);
      assertThat(dto.getPausesNecessaires()).isFalse();
    }
  }
}

