package dev.lions.user.manager.server.impl.entity;

import dev.lions.user.manager.enums.audit.TypeActionAudit;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.time.LocalDateTime;

/**
 * Entité JPA pour la persistance des logs d'audit en base de données PostgreSQL.
 *
 * <p>Cette entité représente un enregistrement d'audit qui track toutes les actions
 * effectuées sur les utilisateurs du système (création, modification, suppression, etc.).</p>
 *
 * <p><b>Utilisation:</b></p>
 * <pre>
 * AuditLogEntity auditLog = new AuditLogEntity();
 * auditLog.setUserId("user-123");
 * auditLog.setAction(TypeActionAudit.CREATION_UTILISATEUR);
 * auditLog.setDetails("Utilisateur créé avec succès");
 * auditLog.setAuteurAction("admin");
 * auditLog.setTimestamp(LocalDateTime.now());
 * auditLog.persist();
 * </pre>
 *
 * @see dev.lions.user.manager.server.api.dto.AuditLogDTO
 * @see TypeActionAudit
 * @author Lions Development Team
 * @version 1.0.0
 * @since 2026-01-02
 */
@Entity
@Table(
    name = "audit_logs",
    indexes = {
        @Index(name = "idx_audit_user_id", columnList = "user_id"),
        @Index(name = "idx_audit_action", columnList = "action"),
        @Index(name = "idx_audit_timestamp", columnList = "timestamp"),
        @Index(name = "idx_audit_auteur", columnList = "auteur_action")
    }
)
@Data
@EqualsAndHashCode(callSuper = true)
public class AuditLogEntity extends PanacheEntity {

    /**
     * ID de l'utilisateur concerné par l'action.
     * <p>Peut être null pour les actions système qui ne concernent pas un utilisateur spécifique.</p>
     */
    @Column(name = "user_id", length = 255)
    private String userId;

    /**
     * Type d'action effectuée (CREATION_UTILISATEUR, MODIFICATION_UTILISATEUR, etc.).
     * <p>Stocké en tant que STRING pour faciliter la lecture en base de données.</p>
     */
    @Column(name = "action", nullable = false, length = 100)
    @Enumerated(EnumType.STRING)
    private TypeActionAudit action;

    /**
     * Détails complémentaires sur l'action effectuée.
     * <p>Peut contenir des informations contextuelles comme les champs modifiés,
     * les raisons d'une action, ou des messages d'erreur.</p>
     */
    @Column(name = "details", columnDefinition = "TEXT")
    private String details;

    /**
     * Identifiant de l'utilisateur qui a effectué l'action.
     * <p>Généralement l'username ou l'ID de l'administrateur/utilisateur connecté.</p>
     */
    @Column(name = "auteur_action", nullable = false, length = 255)
    private String auteurAction;

    /**
     * Timestamp précis de l'action.
     * <p>Utilisé pour l'ordre chronologique des logs et le filtrage temporel.</p>
     */
    @Column(name = "timestamp", nullable = false)
    private LocalDateTime timestamp;

    /**
     * Adresse IP de l'auteur de l'action.
     * <p>Utile pour la traçabilité et la détection d'anomalies.</p>
     */
    @Column(name = "ip_address", length = 45)
    private String ipAddress;

    /**
     * User-Agent du client (navigateur, application, etc.).
     * <p>Permet d'identifier le type de client utilisé pour l'action.</p>
     */
    @Column(name = "user_agent", length = 500)
    private String userAgent;

    /**
     * Nom du realm Keycloak concerné.
     * <p>Important dans un environnement multi-tenant pour isoler les logs par realm.</p>
     */
    @Column(name = "realm_name", length = 255)
    private String realmName;

    /**
     * Indique si l'action a réussi ou échoué.
     * <p>Permet de filtrer facilement les actions en erreur pour analyse.</p>
     */
    @Column(name = "success", nullable = false)
    private Boolean success = true;

    /**
     * Message d'erreur en cas d'échec de l'action.
     * <p>Null si success = true.</p>
     */
    @Column(name = "error_message", columnDefinition = "TEXT")
    private String errorMessage;

    /**
     * Constructeur par défaut requis par JPA.
     */
    public AuditLogEntity() {
        this.timestamp = LocalDateTime.now();
    }

    /**
     * Recherche tous les logs d'audit pour un utilisateur donné.
     *
     * @param userId ID de l'utilisateur
     * @return Liste des logs triés par timestamp décroissant
     */
    public static java.util.List<AuditLogEntity> findByUserId(String userId) {
        return list("userId = ?1 order by timestamp desc", userId);
    }

    /**
     * Recherche tous les logs d'audit d'un type d'action donné.
     *
     * @param action Type d'action
     * @return Liste des logs triés par timestamp décroissant
     */
    public static java.util.List<AuditLogEntity> findByAction(TypeActionAudit action) {
        return list("action = ?1 order by timestamp desc", action);
    }

    /**
     * Recherche tous les logs d'audit pour un auteur donné.
     *
     * @param auteurAction Identifiant de l'auteur
     * @return Liste des logs triés par timestamp décroissant
     */
    public static java.util.List<AuditLogEntity> findByAuteur(String auteurAction) {
        return list("auteurAction = ?1 order by timestamp desc", auteurAction);
    }

    /**
     * Recherche tous les logs d'audit dans une période donnée.
     *
     * @param startDate Date de début (inclusive)
     * @param endDate Date de fin (inclusive)
     * @return Liste des logs dans la période, triés par timestamp décroissant
     */
    public static java.util.List<AuditLogEntity> findByPeriod(LocalDateTime startDate, LocalDateTime endDate) {
        return list("timestamp >= ?1 and timestamp <= ?2 order by timestamp desc", startDate, endDate);
    }

    /**
     * Recherche tous les logs d'audit pour un realm donné.
     *
     * @param realmName Nom du realm
     * @return Liste des logs triés par timestamp décroissant
     */
    public static java.util.List<AuditLogEntity> findByRealm(String realmName) {
        return list("realmName = ?1 order by timestamp desc", realmName);
    }

    /**
     * Supprime tous les logs d'audit plus anciens qu'une date donnée.
     * <p>Utile pour la maintenance et le respect des politiques de rétention.</p>
     *
     * @param beforeDate Date limite (les logs avant cette date seront supprimés)
     * @return Nombre de logs supprimés
     */
    public static long deleteOlderThan(LocalDateTime beforeDate) {
        return delete("timestamp < ?1", beforeDate);
    }

    /**
     * Compte le nombre d'actions effectuées par un auteur donné.
     *
     * @param auteurAction Identifiant de l'auteur
     * @return Nombre d'actions
     */
    public static long countByAuteur(String auteurAction) {
        return count("auteurAction = ?1", auteurAction);
    }

    /**
     * Compte le nombre d'échecs pour un utilisateur donné.
     * <p>Utile pour détecter des problèmes récurrents.</p>
     *
     * @param userId ID de l'utilisateur
     * @return Nombre d'échecs
     */
    public static long countFailuresByUserId(String userId) {
        return count("userId = ?1 and success = false", userId);
    }
}
