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

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.lions.unionflow.server.api.enums.notification.CanalNotification;
import dev.lions.unionflow.server.api.enums.notification.TypeNotification;
import jakarta.validation.constraints.*;
import java.time.LocalTime;
import java.util.Map;
import java.util.Set;

/**
 * DTO pour les préférences de notification d'un utilisateur
 *
 * <p>Ce DTO représente les préférences personnalisées d'un utilisateur concernant la réception et
 * l'affichage des notifications.
 *
 * @author UnionFlow Team
 * @version 1.0
 * @since 2025-01-16
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class PreferencesNotificationDTO {

  /** Identifiant unique des préférences */
  private String id;

  /** Identifiant de l'utilisateur */
  @NotBlank(message = "L'identifiant utilisateur est obligatoire")
  private String utilisateurId;

  /** Identifiant de l'organisation */
  private String organisationId;

  /** Indique si les notifications sont activées globalement */
  @NotNull(message = "L'activation globale des notifications est obligatoire")
  private Boolean notificationsActivees;

  /** Indique si les notifications push sont activées */
  private Boolean pushActivees;

  /** Indique si les notifications par email sont activées */
  private Boolean emailActivees;

  /** Indique si les notifications SMS sont activées */
  private Boolean smsActivees;

  /** Indique si les notifications in-app sont activées */
  private Boolean inAppActivees;

  /** Types de notifications activés */
  private Set<TypeNotification> typesActives;

  /** Types de notifications désactivés */
  private Set<TypeNotification> typesDesactivees;

  /** Canaux de notification activés */
  private Set<CanalNotification> canauxActifs;

  /** Canaux de notification désactivés */
  private Set<CanalNotification> canauxDesactives;

  /** Mode Ne Pas Déranger activé */
  private Boolean modeSilencieux;

  /** Heure de début du mode silencieux */
  @JsonFormat(pattern = "HH:mm")
  private LocalTime heureDebutSilencieux;

  /** Heure de fin du mode silencieux */
  @JsonFormat(pattern = "HH:mm")
  private LocalTime heureFinSilencieux;

  /** Jours de la semaine pour le mode silencieux (1=Lundi, 7=Dimanche) */
  private Set<Integer> joursSilencieux;

  /** Indique si les notifications urgentes passent outre le mode silencieux */
  private Boolean urgentesIgnorentSilencieux;

  /** Fréquence de regroupement des notifications (minutes) */
  @Min(value = 0, message = "La fréquence de regroupement doit être positive")
  @Max(value = 1440, message = "La fréquence de regroupement ne peut pas dépasser 24h")
  private Integer frequenceRegroupementMinutes;

  /** Nombre maximum de notifications affichées simultanément */
  @Min(value = 1, message = "Le nombre maximum de notifications doit être au moins 1")
  @Max(value = 50, message = "Le nombre maximum de notifications ne peut pas dépasser 50")
  private Integer maxNotificationsSimultanees;

  /** Durée d'affichage par défaut des notifications (secondes) */
  @Min(value = 1, message = "La durée d'affichage doit être au moins 1 seconde")
  @Max(value = 300, message = "La durée d'affichage ne peut pas dépasser 5 minutes")
  private Integer dureeAffichageSecondes;

  /** Indique si les notifications doivent vibrer */
  private Boolean vibrationActivee;

  /** Indique si les notifications doivent émettre un son */
  private Boolean sonActive;

  /** Indique si la LED doit s'allumer */
  private Boolean ledActivee;

  /** Son personnalisé pour les notifications */
  private String sonPersonnalise;

  /** Pattern de vibration personnalisé */
  private long[] patternVibrationPersonnalise;

  /** Couleur de LED personnalisée */
  private String couleurLEDPersonnalisee;

  /** Indique si les aperçus de contenu sont affichés sur l'écran de verrouillage */
  private Boolean apercuEcranVerrouillage;

  /** Indique si les notifications sont affichées dans l'historique */
  private Boolean affichageHistorique;

  /** Durée de conservation dans l'historique (jours) */
  @Min(value = 1, message = "La durée de conservation doit être au moins 1 jour")
  @Max(value = 365, message = "La durée de conservation ne peut pas dépasser 1 an")
  private Integer dureeConservationJours;

  /** Indique si les notifications sont automatiquement marquées comme lues */
  private Boolean marquageLectureAutomatique;

  /** Délai avant marquage automatique comme lu (secondes) */
  private Integer delaiMarquageLectureSecondes;

  /** Indique si les notifications sont automatiquement archivées */
  private Boolean archivageAutomatique;

  /** Délai avant archivage automatique (heures) */
  private Integer delaiArchivageHeures;

  /** Préférences par type de notification */
  private Map<TypeNotification, PreferenceTypeNotificationDTO> preferencesParType;

  /** Préférences par canal de notification */
  private Map<CanalNotification, PreferenceCanalNotificationDTO> preferencesParCanal;

  /** Mots-clés pour filtrage automatique */
  private Set<String> motsClesFiltre;

  /** Expéditeurs bloqués */
  private Set<String> expediteursBloqués;

  /** Expéditeurs prioritaires */
  private Set<String> expediteursPrioritaires;

  /** Indique si les notifications de test sont activées */
  private Boolean notificationsTestActivees;

  /** Niveau de log pour les notifications (DEBUG, INFO, WARN, ERROR) */
  private String niveauLog;

  /** Token FCM pour les notifications push */
  private String tokenFCM;

  /** Plateforme de l'appareil (android, ios, web) */
  private String plateforme;

  /** Version de l'application */
  private String versionApp;

  /** Langue préférée pour les notifications */
  private String langue;

  /** Fuseau horaire de l'utilisateur */
  private String fuseauHoraire;

  /** Métadonnées personnalisées */
  private Map<String, Object> metadonnees;

  // === CONSTRUCTEURS ===

  /** Constructeur par défaut avec valeurs par défaut */
  public PreferencesNotificationDTO() {
    this.notificationsActivees = true;
    this.pushActivees = true;
    this.emailActivees = true;
    this.smsActivees = false;
    this.inAppActivees = true;
    this.modeSilencieux = false;
    this.urgentesIgnorentSilencieux = true;
    this.frequenceRegroupementMinutes = 5;
    this.maxNotificationsSimultanees = 10;
    this.dureeAffichageSecondes = 10;
    this.vibrationActivee = true;
    this.sonActive = true;
    this.ledActivee = true;
    this.apercuEcranVerrouillage = true;
    this.affichageHistorique = true;
    this.dureeConservationJours = 30;
    this.marquageLectureAutomatique = false;
    this.archivageAutomatique = true;
    this.delaiArchivageHeures = 168; // 1 semaine
    this.notificationsTestActivees = false;
    this.niveauLog = "INFO";
    this.langue = "fr";
  }

  /** Constructeur avec utilisateur */
  public PreferencesNotificationDTO(String utilisateurId) {
    this();
    this.utilisateurId = utilisateurId;
  }

  // === GETTERS ET SETTERS ===

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getUtilisateurId() {
    return utilisateurId;
  }

  public void setUtilisateurId(String utilisateurId) {
    this.utilisateurId = utilisateurId;
  }

  public String getOrganisationId() {
    return organisationId;
  }

  public void setOrganisationId(String organisationId) {
    this.organisationId = organisationId;
  }

  public Boolean getNotificationsActivees() {
    return notificationsActivees;
  }

  public void setNotificationsActivees(Boolean notificationsActivees) {
    this.notificationsActivees = notificationsActivees;
  }

  public Boolean getPushActivees() {
    return pushActivees;
  }

  public void setPushActivees(Boolean pushActivees) {
    this.pushActivees = pushActivees;
  }

  public Boolean getEmailActivees() {
    return emailActivees;
  }

  public void setEmailActivees(Boolean emailActivees) {
    this.emailActivees = emailActivees;
  }

  public Boolean getSmsActivees() {
    return smsActivees;
  }

  public void setSmsActivees(Boolean smsActivees) {
    this.smsActivees = smsActivees;
  }

  public Boolean getInAppActivees() {
    return inAppActivees;
  }

  public void setInAppActivees(Boolean inAppActivees) {
    this.inAppActivees = inAppActivees;
  }

  public Set<TypeNotification> getTypesActives() {
    return typesActives;
  }

  public void setTypesActives(Set<TypeNotification> typesActives) {
    this.typesActives = typesActives;
  }

  public Set<TypeNotification> getTypesDesactivees() {
    return typesDesactivees;
  }

  public void setTypesDesactivees(Set<TypeNotification> typesDesactivees) {
    this.typesDesactivees = typesDesactivees;
  }

  public Set<CanalNotification> getCanauxActifs() {
    return canauxActifs;
  }

  public void setCanauxActifs(Set<CanalNotification> canauxActifs) {
    this.canauxActifs = canauxActifs;
  }

  public Set<CanalNotification> getCanauxDesactives() {
    return canauxDesactives;
  }

  public void setCanauxDesactives(Set<CanalNotification> canauxDesactives) {
    this.canauxDesactives = canauxDesactives;
  }

  public Boolean getModeSilencieux() {
    return modeSilencieux;
  }

  public void setModeSilencieux(Boolean modeSilencieux) {
    this.modeSilencieux = modeSilencieux;
  }

  public LocalTime getHeureDebutSilencieux() {
    return heureDebutSilencieux;
  }

  public void setHeureDebutSilencieux(LocalTime heureDebutSilencieux) {
    this.heureDebutSilencieux = heureDebutSilencieux;
  }

  public LocalTime getHeureFinSilencieux() {
    return heureFinSilencieux;
  }

  public void setHeureFinSilencieux(LocalTime heureFinSilencieux) {
    this.heureFinSilencieux = heureFinSilencieux;
  }

  public Set<Integer> getJoursSilencieux() {
    return joursSilencieux;
  }

  public void setJoursSilencieux(Set<Integer> joursSilencieux) {
    this.joursSilencieux = joursSilencieux;
  }

  public Boolean getUrgentesIgnorentSilencieux() {
    return urgentesIgnorentSilencieux;
  }

  public void setUrgentesIgnorentSilencieux(Boolean urgentesIgnorentSilencieux) {
    this.urgentesIgnorentSilencieux = urgentesIgnorentSilencieux;
  }

  public Integer getFrequenceRegroupementMinutes() {
    return frequenceRegroupementMinutes;
  }

  public void setFrequenceRegroupementMinutes(Integer frequenceRegroupementMinutes) {
    this.frequenceRegroupementMinutes = frequenceRegroupementMinutes;
  }

  public Integer getMaxNotificationsSimultanees() {
    return maxNotificationsSimultanees;
  }

  public void setMaxNotificationsSimultanees(Integer maxNotificationsSimultanees) {
    this.maxNotificationsSimultanees = maxNotificationsSimultanees;
  }

  public Integer getDureeAffichageSecondes() {
    return dureeAffichageSecondes;
  }

  public void setDureeAffichageSecondes(Integer dureeAffichageSecondes) {
    this.dureeAffichageSecondes = dureeAffichageSecondes;
  }

  public Boolean getVibrationActivee() {
    return vibrationActivee;
  }

  public void setVibrationActivee(Boolean vibrationActivee) {
    this.vibrationActivee = vibrationActivee;
  }

  public Boolean getSonActive() {
    return sonActive;
  }

  public void setSonActive(Boolean sonActive) {
    this.sonActive = sonActive;
  }

  public Boolean getLedActivee() {
    return ledActivee;
  }

  public void setLedActivee(Boolean ledActivee) {
    this.ledActivee = ledActivee;
  }

  public String getSonPersonnalise() {
    return sonPersonnalise;
  }

  public void setSonPersonnalise(String sonPersonnalise) {
    this.sonPersonnalise = sonPersonnalise;
  }

  public long[] getPatternVibrationPersonnalise() {
    return patternVibrationPersonnalise;
  }

  public void setPatternVibrationPersonnalise(long[] patternVibrationPersonnalise) {
    this.patternVibrationPersonnalise = patternVibrationPersonnalise;
  }

  public String getCouleurLEDPersonnalisee() {
    return couleurLEDPersonnalisee;
  }

  public void setCouleurLEDPersonnalisee(String couleurLEDPersonnalisee) {
    this.couleurLEDPersonnalisee = couleurLEDPersonnalisee;
  }

  public Boolean getApercuEcranVerrouillage() {
    return apercuEcranVerrouillage;
  }

  public void setApercuEcranVerrouillage(Boolean apercuEcranVerrouillage) {
    this.apercuEcranVerrouillage = apercuEcranVerrouillage;
  }

  public Boolean getAffichageHistorique() {
    return affichageHistorique;
  }

  public void setAffichageHistorique(Boolean affichageHistorique) {
    this.affichageHistorique = affichageHistorique;
  }

  public Integer getDureeConservationJours() {
    return dureeConservationJours;
  }

  public void setDureeConservationJours(Integer dureeConservationJours) {
    this.dureeConservationJours = dureeConservationJours;
  }

  public Boolean getMarquageLectureAutomatique() {
    return marquageLectureAutomatique;
  }

  public void setMarquageLectureAutomatique(Boolean marquageLectureAutomatique) {
    this.marquageLectureAutomatique = marquageLectureAutomatique;
  }

  public Integer getDelaiMarquageLectureSecondes() {
    return delaiMarquageLectureSecondes;
  }

  public void setDelaiMarquageLectureSecondes(Integer delaiMarquageLectureSecondes) {
    this.delaiMarquageLectureSecondes = delaiMarquageLectureSecondes;
  }

  public Boolean getArchivageAutomatique() {
    return archivageAutomatique;
  }

  public void setArchivageAutomatique(Boolean archivageAutomatique) {
    this.archivageAutomatique = archivageAutomatique;
  }

  public Integer getDelaiArchivageHeures() {
    return delaiArchivageHeures;
  }

  public void setDelaiArchivageHeures(Integer delaiArchivageHeures) {
    this.delaiArchivageHeures = delaiArchivageHeures;
  }

  public Map<TypeNotification, PreferenceTypeNotificationDTO> getPreferencesParType() {
    return preferencesParType;
  }

  public void setPreferencesParType(
      Map<TypeNotification, PreferenceTypeNotificationDTO> preferencesParType) {
    this.preferencesParType = preferencesParType;
  }

  public Map<CanalNotification, PreferenceCanalNotificationDTO> getPreferencesParCanal() {
    return preferencesParCanal;
  }

  public void setPreferencesParCanal(
      Map<CanalNotification, PreferenceCanalNotificationDTO> preferencesParCanal) {
    this.preferencesParCanal = preferencesParCanal;
  }

  public Set<String> getMotsClesFiltre() {
    return motsClesFiltre;
  }

  public void setMotsClesFiltre(Set<String> motsClesFiltre) {
    this.motsClesFiltre = motsClesFiltre;
  }

  public Set<String> getExpediteursBloques() {
    return expediteursBloqués;
  }

  public void setExpediteursBloques(Set<String> expediteursBloqués) {
    this.expediteursBloqués = expediteursBloqués;
  }

  public Set<String> getExpediteursPrioritaires() {
    return expediteursPrioritaires;
  }

  public void setExpediteursPrioritaires(Set<String> expediteursPrioritaires) {
    this.expediteursPrioritaires = expediteursPrioritaires;
  }

  public Boolean getNotificationsTestActivees() {
    return notificationsTestActivees;
  }

  public void setNotificationsTestActivees(Boolean notificationsTestActivees) {
    this.notificationsTestActivees = notificationsTestActivees;
  }

  public String getNiveauLog() {
    return niveauLog;
  }

  public void setNiveauLog(String niveauLog) {
    this.niveauLog = niveauLog;
  }

  public String getTokenFCM() {
    return tokenFCM;
  }

  public void setTokenFCM(String tokenFCM) {
    this.tokenFCM = tokenFCM;
  }

  public String getPlateforme() {
    return plateforme;
  }

  public void setPlateforme(String plateforme) {
    this.plateforme = plateforme;
  }

  public String getVersionApp() {
    return versionApp;
  }

  public void setVersionApp(String versionApp) {
    this.versionApp = versionApp;
  }

  public String getLangue() {
    return langue;
  }

  public void setLangue(String langue) {
    this.langue = langue;
  }

  public String getFuseauHoraire() {
    return fuseauHoraire;
  }

  public void setFuseauHoraire(String fuseauHoraire) {
    this.fuseauHoraire = fuseauHoraire;
  }

  public Map<String, Object> getMetadonnees() {
    return metadonnees;
  }

  public void setMetadonnees(Map<String, Object> metadonnees) {
    this.metadonnees = metadonnees;
  }

  // === MÉTHODES UTILITAIRES ===

  /** Vérifie si un type de notification est activé */
  public boolean isTypeActive(TypeNotification type) {
    if (!notificationsActivees) return false;
    if (typesDesactivees != null && typesDesactivees.contains(type)) return false;
    if (typesActives != null) return typesActives.contains(type);
    return type.isActiveeParDefaut();
  }

  /** Vérifie si un canal de notification est activé */
  public boolean isCanalActif(CanalNotification canal) {
    if (!notificationsActivees) return false;
    if (canauxDesactives != null && canauxDesactives.contains(canal)) return false;
    if (canauxActifs != null) return canauxActifs.contains(canal);
    return true;
  }

  /** 
   * Version de test de isEnModeSilencieux avec une heure fixe
   * Permet de tester toutes les branches sans dépendre de l'heure actuelle
   */
  boolean isEnModeSilencieux(LocalTime heureActuelle) {
    if (!modeSilencieux) return false;
    if (heureDebutSilencieux == null || heureFinSilencieux == null) return false;

    // Gestion du cas où la période traverse minuit
    if (heureDebutSilencieux.isAfter(heureFinSilencieux)) {
      return heureActuelle.isAfter(heureDebutSilencieux) || heureActuelle.isBefore(heureFinSilencieux);
    } else {
      return heureActuelle.isAfter(heureDebutSilencieux) && heureActuelle.isBefore(heureFinSilencieux);
    }
  }

  /** Vérifie si on est en mode silencieux actuellement */
  public boolean isEnModeSilencieux() {
    return isEnModeSilencieux(LocalTime.now());
  }

  /** Vérifie si un expéditeur est bloqué */
  public boolean isExpediteurBloque(String expediteurId) {
    return expediteursBloqués != null && expediteursBloqués.contains(expediteurId);
  }

  /** Vérifie si un expéditeur est prioritaire */
  public boolean isExpediteurPrioritaire(String expediteurId) {
    return expediteursPrioritaires != null && expediteursPrioritaires.contains(expediteurId);
  }

  @Override
  public String toString() {
    return String.format(
        "PreferencesNotificationDTO{utilisateurId='%s', notificationsActivees=%s}",
        utilisateurId, notificationsActivees);
  }
}
