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

import static dev.lions.unionflow.server.api.TestDataFactory.createNotificationDTO;
import static dev.lions.unionflow.server.api.TestDataFactory.now;
import static org.assertj.core.api.Assertions.assertThat;

import dev.lions.unionflow.server.api.enums.notification.CanalNotification;
import dev.lions.unionflow.server.api.enums.notification.StatutNotification;
import dev.lions.unionflow.server.api.enums.notification.TypeNotification;
import java.time.LocalDateTime;
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.CsvSource;

@DisplayName("Tests pour NotificationDTO")
class NotificationDTOTest {

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

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

    @Test
    @DisplayName("Constructeur par défaut initialise correctement")
    void testConstructeurParDefaut() {
      NotificationDTO notification = new NotificationDTO();

      assertThat(notification.getDateCreation()).isNotNull();
      assertThat(notification.getStatut()).isEqualTo(StatutNotification.BROUILLON);
      assertThat(notification.getNombreTentatives()).isEqualTo(0);
      assertThat(notification.getMaxTentatives()).isEqualTo(3);
      assertThat(notification.getDelaiTentativesMinutes()).isEqualTo(5);
      assertThat(notification.getEstLue()).isFalse();
      assertThat(notification.getEstImportante()).isFalse();
      assertThat(notification.getEstArchivee()).isFalse();
      assertThat(notification.getNombreAffichages()).isEqualTo(0);
      assertThat(notification.getNombreClics()).isEqualTo(0);
    }

    @Test
    @DisplayName("Constructeur avec paramètres essentiels")
    void testConstructeurAvecParametres() {
      NotificationDTO notification = new NotificationDTO(
          TypeNotification.NOUVEL_EVENEMENT,
          "Titre",
          "Message",
          List.of("user1", "user2"));

      assertThat(notification.getTypeNotification()).isEqualTo(TypeNotification.NOUVEL_EVENEMENT);
      assertThat(notification.getTitre()).isEqualTo("Titre");
      assertThat(notification.getMessage()).isEqualTo("Message");
      assertThat(notification.getDestinatairesIds()).containsExactly("user1", "user2");
      assertThat(notification.getCanal()).isNotNull();
      assertThat(notification.getPriorite()).isNotNull();
    }
  }

  @Nested
  @DisplayName("Tests isExpiree")
  class IsExpireeTests {

    @Test
    @DisplayName("isExpiree - notification expirée")
    void testIsExpiree() {
      NotificationDTO notification = createNotificationDTO();
      notification.setDateExpiration(now().minusHours(1));

      assertThat(notification.isExpiree()).isTrue();
    }

    @Test
    @DisplayName("isExpiree - notification non expirée")
    void testIsExpireeNonExpiree() {
      NotificationDTO notification = createNotificationDTO();
      notification.setDateExpiration(now().plusHours(1));

      assertThat(notification.isExpiree()).isFalse();
    }

    @Test
    @DisplayName("isExpiree - dateExpiration null")
    void testIsExpireeNull() {
      NotificationDTO notification = createNotificationDTO();

      assertThat(notification.isExpiree()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests peutEtreRenvoyee")
  class PeutEtreRenvoyeeTests {

    @Test
    @DisplayName("peutEtreRenvoyee - peut être renvoyée")
    void testPeutEtreRenvoyee() {
      NotificationDTO notification = createNotificationDTO();
      notification.setNombreTentatives(1);
      notification.setMaxTentatives(3);
      notification.setStatut(StatutNotification.EN_ATTENTE);

      assertThat(notification.peutEtreRenvoyee()).isTrue();
    }

    @Test
    @DisplayName("peutEtreRenvoyee - max tentatives atteint")
    void testPeutEtreRenvoyeeMaxTentatives() {
      NotificationDTO notification = createNotificationDTO();
      notification.setNombreTentatives(3);
      notification.setMaxTentatives(3);

      assertThat(notification.peutEtreRenvoyee()).isFalse();
    }

    @Test
    @DisplayName("peutEtreRenvoyee - statut final")
    void testPeutEtreRenvoyeeStatutFinal() {
      NotificationDTO notification = createNotificationDTO();
      notification.setStatut(StatutNotification.SUPPRIMEE); // Statut final

      assertThat(notification.peutEtreRenvoyee()).isFalse();
    }
  }

  @Nested
  @DisplayName("Tests getTauxEngagement")
  class GetTauxEngagementTests {

    @ParameterizedTest
    @CsvSource({
        "100, 50, 50.0",
        "100, 100, 100.0",
        "100, 0, 0.0",
        "200, 100, 50.0"
    })
    @DisplayName("getTauxEngagement - calculs variés")
    void testGetTauxEngagement(Integer affichages, Integer clics, Double expected) {
      NotificationDTO notification = createNotificationDTO();
      notification.setNombreAffichages(affichages);
      notification.setNombreClics(clics);

      assertThat(notification.getTauxEngagement()).isEqualTo(expected);
    }

    @Test
    @DisplayName("getTauxEngagement - nombreAffichages = 0")
    void testGetTauxEngagementZeroAffichages() {
      NotificationDTO notification = createNotificationDTO();
      notification.setNombreAffichages(0);
      notification.setNombreClics(10);

      assertThat(notification.getTauxEngagement()).isEqualTo(0.0);
    }
  }

  @Nested
  @DisplayName("Tests toString")
  class ToStringTests {

    @Test
    @DisplayName("toString contient les informations essentielles")
    void testToString() {
      NotificationDTO notification = createNotificationDTO();
      notification.setId("notif-123");
      notification.setTypeNotification(TypeNotification.NOUVEL_EVENEMENT);
      notification.setStatut(StatutNotification.EN_ATTENTE);
      notification.setTitre("Test Notification");

      String toString = notification.toString();

      assertThat(toString).contains("NotificationDTO");
      assertThat(toString).contains("notif-123");
      assertThat(toString).contains("NOUVEL_EVENEMENT");
      assertThat(toString).contains("EN_ATTENTE");
      assertThat(toString).contains("Test Notification");
    }
  }

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

    @Test
    @DisplayName("Test tous les getters/setters")
    void testTousLesGettersSetters() {
      NotificationDTO notification = new NotificationDTO();
      LocalDateTime date1 = LocalDateTime.of(2025, 1, 15, 10, 0);
      LocalDateTime date2 = LocalDateTime.of(2025, 1, 15, 11, 0);
      LocalDateTime date3 = LocalDateTime.of(2025, 1, 15, 12, 0);
      LocalDateTime date4 = LocalDateTime.of(2025, 1, 15, 13, 0);
      LocalDateTime date5 = LocalDateTime.of(2025, 1, 15, 14, 0);
      List<String> destinataires = List.of("user1", "user2");
      List<ActionNotificationDTO> actions = List.of(new ActionNotificationDTO());
      java.util.Map<String, Object> donnees = new java.util.HashMap<>();
      donnees.put("key", "value");
      java.util.Map<String, String> parametres = new java.util.HashMap<>();
      parametres.put("param", "value");
      java.util.Map<String, Object> metadonnees = new java.util.HashMap<>();
      metadonnees.put("meta", "data");
      List<String> tags = List.of("tag1", "tag2");
      long[] pattern = new long[]{100, 200, 300};

      // Test tous les setters/getters
      notification.setId("id-123");
      notification.setTypeNotification(TypeNotification.NOUVEL_EVENEMENT);
      notification.setStatut(StatutNotification.EN_ATTENTE);
      notification.setCanal(CanalNotification.URGENT_CHANNEL);
      notification.setTitre("Titre");
      notification.setMessage("Message");
      notification.setMessageCourt("Message court");
      notification.setExpediteurId("expediteur-id");
      notification.setExpediteurNom("Expediteur Nom");
      notification.setDestinatairesIds(destinataires);
      notification.setOrganisationId("org-id");
      notification.setDonneesPersonnalisees(donnees);
      notification.setImageUrl("https://example.com/image.jpg");
      notification.setIconeUrl("https://example.com/icon.png");
      notification.setActionClic("action");
      notification.setParametresAction(parametres);
      notification.setActionsRapides(actions);
      notification.setDateCreation(date1);
      notification.setDateEnvoiProgramme(date2);
      notification.setDateEnvoi(date3);
      notification.setDateExpiration(date4);
      notification.setDateDerniereLecture(date5);
      notification.setPriorite(5);
      notification.setNombreTentatives(2);
      notification.setMaxTentatives(5);
      notification.setDelaiTentativesMinutes(10);
      notification.setDoitVibrer(true);
      notification.setDoitEmettreSon(true);
      notification.setDoitAllumerLED(true);
      notification.setPatternVibration(pattern);
      notification.setSonPersonnalise("son.mp3");
      notification.setCouleurLED("#FF0000");
      notification.setEstLue(true);
      notification.setEstImportante(true);
      notification.setEstArchivee(true);
      notification.setNombreAffichages(100);
      notification.setNombreClics(50);
      notification.setTauxLivraison(95.5);
      notification.setTauxOuverture(80.0);
      notification.setTempsMoyenLectureSecondes(30);
      notification.setMessageErreur("Erreur");
      notification.setCodeErreur("ERR001");
      notification.setTraceErreur("Stack trace");
      notification.setMetadonnees(metadonnees);
      notification.setTags(tags);
      notification.setCampagneId("campagne-id");
      notification.setVersionApp("1.0.0");
      notification.setPlateforme("android");
      notification.setTokenFCM("token-fcm");
      notification.setIdSuiviExterne("suivi-externe");

      // Vérifier tous les getters
      assertThat(notification.getId()).isEqualTo("id-123");
      assertThat(notification.getTypeNotification()).isEqualTo(TypeNotification.NOUVEL_EVENEMENT);
      assertThat(notification.getStatut()).isEqualTo(StatutNotification.EN_ATTENTE);
      assertThat(notification.getCanal()).isEqualTo(CanalNotification.URGENT_CHANNEL);
      assertThat(notification.getTitre()).isEqualTo("Titre");
      assertThat(notification.getMessage()).isEqualTo("Message");
      assertThat(notification.getMessageCourt()).isEqualTo("Message court");
      assertThat(notification.getExpediteurId()).isEqualTo("expediteur-id");
      assertThat(notification.getExpediteurNom()).isEqualTo("Expediteur Nom");
      assertThat(notification.getDestinatairesIds()).isEqualTo(destinataires);
      assertThat(notification.getOrganisationId()).isEqualTo("org-id");
      assertThat(notification.getDonneesPersonnalisees()).isEqualTo(donnees);
      assertThat(notification.getImageUrl()).isEqualTo("https://example.com/image.jpg");
      assertThat(notification.getIconeUrl()).isEqualTo("https://example.com/icon.png");
      assertThat(notification.getActionClic()).isEqualTo("action");
      assertThat(notification.getParametresAction()).isEqualTo(parametres);
      assertThat(notification.getActionsRapides()).isEqualTo(actions);
      assertThat(notification.getDateCreation()).isEqualTo(date1);
      assertThat(notification.getDateEnvoiProgramme()).isEqualTo(date2);
      assertThat(notification.getDateEnvoi()).isEqualTo(date3);
      assertThat(notification.getDateExpiration()).isEqualTo(date4);
      assertThat(notification.getDateDerniereLecture()).isEqualTo(date5);
      assertThat(notification.getPriorite()).isEqualTo(5);
      assertThat(notification.getNombreTentatives()).isEqualTo(2);
      assertThat(notification.getMaxTentatives()).isEqualTo(5);
      assertThat(notification.getDelaiTentativesMinutes()).isEqualTo(10);
      assertThat(notification.getDoitVibrer()).isTrue();
      assertThat(notification.getDoitEmettreSon()).isTrue();
      assertThat(notification.getDoitAllumerLED()).isTrue();
      assertThat(notification.getPatternVibration()).isEqualTo(pattern);
      assertThat(notification.getSonPersonnalise()).isEqualTo("son.mp3");
      assertThat(notification.getCouleurLED()).isEqualTo("#FF0000");
      assertThat(notification.getEstLue()).isTrue();
      assertThat(notification.getEstImportante()).isTrue();
      assertThat(notification.getEstArchivee()).isTrue();
      assertThat(notification.getNombreAffichages()).isEqualTo(100);
      assertThat(notification.getNombreClics()).isEqualTo(50);
      assertThat(notification.getTauxLivraison()).isEqualTo(95.5);
      assertThat(notification.getTauxOuverture()).isEqualTo(80.0);
      assertThat(notification.getTempsMoyenLectureSecondes()).isEqualTo(30);
      assertThat(notification.getMessageErreur()).isEqualTo("Erreur");
      assertThat(notification.getCodeErreur()).isEqualTo("ERR001");
      assertThat(notification.getTraceErreur()).isEqualTo("Stack trace");
      assertThat(notification.getMetadonnees()).isEqualTo(metadonnees);
      assertThat(notification.getTags()).isEqualTo(tags);
      assertThat(notification.getCampagneId()).isEqualTo("campagne-id");
      assertThat(notification.getVersionApp()).isEqualTo("1.0.0");
      assertThat(notification.getPlateforme()).isEqualTo("android");
      assertThat(notification.getTokenFCM()).isEqualTo("token-fcm");
      assertThat(notification.getIdSuiviExterne()).isEqualTo("suivi-externe");
    }

    @Test
    @DisplayName("Test getters/setters avec valeurs null")
    void testGettersSettersAvecNull() {
      NotificationDTO notification = new NotificationDTO();

      notification.setId(null);
      notification.setTypeNotification(null);
      notification.setStatut(null);
      notification.setCanal(null);
      notification.setTitre(null);
      notification.setMessage(null);
      notification.setMessageCourt(null);
      notification.setExpediteurId(null);
      notification.setExpediteurNom(null);
      notification.setDestinatairesIds(null);
      notification.setOrganisationId(null);
      notification.setDonneesPersonnalisees(null);
      notification.setImageUrl(null);
      notification.setIconeUrl(null);
      notification.setActionClic(null);
      notification.setParametresAction(null);
      notification.setActionsRapides(null);
      notification.setDateCreation(null);
      notification.setDateEnvoiProgramme(null);
      notification.setDateEnvoi(null);
      notification.setDateExpiration(null);
      notification.setDateDerniereLecture(null);
      notification.setPriorite(null);
      notification.setNombreTentatives(null);
      notification.setMaxTentatives(null);
      notification.setDelaiTentativesMinutes(null);
      notification.setDoitVibrer(null);
      notification.setDoitEmettreSon(null);
      notification.setDoitAllumerLED(null);
      notification.setPatternVibration(null);
      notification.setSonPersonnalise(null);
      notification.setCouleurLED(null);
      notification.setEstLue(null);
      notification.setEstImportante(null);
      notification.setEstArchivee(null);
      notification.setNombreAffichages(null);
      notification.setNombreClics(null);
      notification.setTauxLivraison(null);
      notification.setTauxOuverture(null);
      notification.setTempsMoyenLectureSecondes(null);
      notification.setMessageErreur(null);
      notification.setCodeErreur(null);
      notification.setTraceErreur(null);
      notification.setMetadonnees(null);
      notification.setTags(null);
      notification.setCampagneId(null);
      notification.setVersionApp(null);
      notification.setPlateforme(null);
      notification.setTokenFCM(null);
      notification.setIdSuiviExterne(null);

      assertThat(notification.getId()).isNull();
      assertThat(notification.getTypeNotification()).isNull();
      assertThat(notification.getStatut()).isNull();
      assertThat(notification.getCanal()).isNull();
      assertThat(notification.getTitre()).isNull();
      assertThat(notification.getMessage()).isNull();
      assertThat(notification.getMessageCourt()).isNull();
      assertThat(notification.getExpediteurId()).isNull();
      assertThat(notification.getExpediteurNom()).isNull();
      assertThat(notification.getDestinatairesIds()).isNull();
      assertThat(notification.getOrganisationId()).isNull();
      assertThat(notification.getDonneesPersonnalisees()).isNull();
      assertThat(notification.getImageUrl()).isNull();
      assertThat(notification.getIconeUrl()).isNull();
      assertThat(notification.getActionClic()).isNull();
      assertThat(notification.getParametresAction()).isNull();
      assertThat(notification.getActionsRapides()).isNull();
      assertThat(notification.getDateCreation()).isNull();
      assertThat(notification.getDateEnvoiProgramme()).isNull();
      assertThat(notification.getDateEnvoi()).isNull();
      assertThat(notification.getDateExpiration()).isNull();
      assertThat(notification.getDateDerniereLecture()).isNull();
      assertThat(notification.getPriorite()).isNull();
      assertThat(notification.getNombreTentatives()).isNull();
      assertThat(notification.getMaxTentatives()).isNull();
      assertThat(notification.getDelaiTentativesMinutes()).isNull();
      assertThat(notification.getDoitVibrer()).isNull();
      assertThat(notification.getDoitEmettreSon()).isNull();
      assertThat(notification.getDoitAllumerLED()).isNull();
      assertThat(notification.getPatternVibration()).isNull();
      assertThat(notification.getSonPersonnalise()).isNull();
      assertThat(notification.getCouleurLED()).isNull();
      assertThat(notification.getEstLue()).isNull();
      assertThat(notification.getEstImportante()).isNull();
      assertThat(notification.getEstArchivee()).isNull();
      assertThat(notification.getNombreAffichages()).isNull();
      assertThat(notification.getNombreClics()).isNull();
      assertThat(notification.getTauxLivraison()).isNull();
      assertThat(notification.getTauxOuverture()).isNull();
      assertThat(notification.getTempsMoyenLectureSecondes()).isNull();
      assertThat(notification.getMessageErreur()).isNull();
      assertThat(notification.getCodeErreur()).isNull();
      assertThat(notification.getTraceErreur()).isNull();
      assertThat(notification.getMetadonnees()).isNull();
      assertThat(notification.getTags()).isNull();
      assertThat(notification.getCampagneId()).isNull();
      assertThat(notification.getVersionApp()).isNull();
      assertThat(notification.getPlateforme()).isNull();
      assertThat(notification.getTokenFCM()).isNull();
      assertThat(notification.getIdSuiviExterne()).isNull();
    }
  }
}

