package dev.lions.models;

import dev.lions.utils.JsonConverter;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Table;
import java.time.LocalDateTime;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Représente une notification système à destination d'un utilisateur.
 * Cette classe encapsule les informations nécessaires pour générer, stocker
 * et afficher une notification dans l'application.
 */
@Data
@Entity
@Table(name = "notifications")
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Notification {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(nullable = false)
  private String title;

  @Column(nullable = false, length = 1000)
  private String message;

  @Enumerated(EnumType.STRING)
  @Column(nullable = false)
  private NotificationType type;

  @Enumerated(EnumType.STRING)
  @Column(nullable = false)
  private NotificationStatus status;

  @Column(nullable = false)
  private LocalDateTime timestamp;

  @Column(name = "target_user_id")
  private Long targetUserId;

  @Column(name = "source_entity_type")
  private String sourceEntityType;

  @Column(name = "source_entity_id")
  private Long sourceEntityId;

  @Column(name = "read_timestamp")
  private LocalDateTime readTimestamp;

  @Column(name = "action_url")
  private String actionUrl;

  @Column(name = "notification_data", columnDefinition = "jsonb")
  @Convert(converter = JsonConverter.class)
  private NotificationData data;

  /**
   * Initialise les valeurs par défaut de la notification.
   * La date de création et le statut "non lu" sont définis ici.
   */
  @PrePersist
  protected void onCreate() {
    if (timestamp == null) {
      timestamp = LocalDateTime.now();
    }
    if (status == null) {
      status = NotificationStatus.UNREAD;
    }
  }

  /**
   * Représente les données supplémentaires associées à la notification.
   * Cette classe imbriquée permet de stocker des attributs et métadonnées.
   */
  @Data
  @Builder
  @NoArgsConstructor
  @AllArgsConstructor
  public static class NotificationData {
    private Map<String, Object> attributes;
    private Map<String, String> metadata;
  }

  /**
   * Vérifie si la notification a été marquée comme lue.
   *
   * @return true si la notification a été lue
   */
  public boolean isRead() {
    return NotificationStatus.READ.equals(this.status);
  }

  /**
   * Vérifie si la notification est de type critique.
   *
   * @return true si la notification est critique
   */
  public boolean isCritical() {
    return type != null && type.isCritical();
  }

  /**
   * Marque la notification comme lue.
   * Met à jour le statut et la date de lecture.
   */
  public void markAsRead() {
    this.status = NotificationStatus.READ;
    this.readTimestamp = LocalDateTime.now();
  }
}