package dev.lions.unionflow.server.entity.listener;

import dev.lions.unionflow.server.entity.BaseEntity;
import dev.lions.unionflow.server.service.KeycloakService;
import io.quarkus.arc.Arc;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import org.jboss.logging.Logger;

/**
 * Listener JPA pour l'alimentation automatique
 * des champs d'audit.
 *
 * <p>
 * Renseigne automatiquement {@code creePar} lors
 * de la création et {@code modifiePar} lors de la
 * mise à jour, en récupérant l'email de
 * l'utilisateur authentifié via
 * {@link KeycloakService}.
 *
 * <p>
 * Ce listener est référencé via
 * {@code @EntityListeners} sur {@link BaseEntity},
 * garantissant que <strong>toutes</strong> les
 * entités héritent automatiquement de ce
 * comportement (WOU strict).
 *
 * @author UnionFlow Team
 * @version 3.0
 * @since 2026-02-21
 */
public class AuditEntityListener {

    /**
     * Utilisateur par défaut pour les opérations
     * système sans contexte de sécurité.
     */
    private static final String UTILISATEUR_SYSTEME = "system";

    private static final Logger LOG = Logger.getLogger(AuditEntityListener.class);

    /**
     * Callback exécuté avant la persistance.
     *
     * <p>
     * Renseigne {@code creePar} avec l'email
     * de l'utilisateur authentifié, ou
     * {@code "system"} si aucun contexte de
     * sécurité n'est disponible.
     *
     * @param entity l'entité en cours de création
     */
    @PrePersist
    public void avantCreation(BaseEntity entity) {
        if (entity.getCreePar() == null
                || entity.getCreePar().isBlank()) {
            entity.setCreePar(
                    obtenirUtilisateurCourant());
        }
    }

    /**
     * Callback exécuté avant la mise à jour.
     *
     * <p>
     * Renseigne {@code modifiePar} avec l'email
     * de l'utilisateur authentifié.
     *
     * @param entity l'entité en cours de modification
     */
    @PreUpdate
    public void avantModification(BaseEntity entity) {
        entity.setModifiePar(
                obtenirUtilisateurCourant());
    }

    /**
     * Obtient l'email de l'utilisateur courant.
     *
     * <p>
     * Utilise {@link Arc#container()} pour
     * résoudre le {@link KeycloakService} depuis
     * le conteneur CDI de Quarkus.
     *
     * @return l'email ou {@code "system"} en fallback
     */
    private String obtenirUtilisateurCourant() {
        try {
            KeycloakService keycloakService = Arc.container()
                    .instance(KeycloakService.class)
                    .get();
            if (keycloakService != null
                    && keycloakService.isAuthenticated()) {
                String email = keycloakService.getCurrentUserEmail();
                if (email != null && !email.isBlank()) {
                    return email;
                }
            }
        } catch (Exception e) {
            LOG.debugf(
                    "Contexte de sécurité indisponible: %s",
                    e.getMessage());
        }
        return UTILISATEUR_SYSTEME;
    }
}
