package dev.lions.user.manager.dto.audit;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import dev.lions.user.manager.dto.base.BaseDTO;
import dev.lions.user.manager.enums.audit.TypeActionAudit;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import org.eclipse.microprofile.openapi.annotations.media.Schema;

import java.time.LocalDateTime;
import java.util.Map;

/**
 * DTO représentant une entrée d'audit
 * Enregistre toutes les actions effectuées via l'API de gestion
 */
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
@Schema(description = "Entrée d'audit des actions utilisateur")
public class AuditLogDTO extends BaseDTO {

    private static final long serialVersionUID = 1L;

    // Qui a fait l'action
    @Schema(description = "ID de l'utilisateur qui a effectué l'action", example = "f47ac10b-58cc-4372-a567-0e02b2c3d479")
    private String acteurUserId;

    @Schema(description = "Username de l'utilisateur qui a effectué l'action", example = "admin@lions.dev")
    private String acteurUsername;

    @Schema(description = "Nom complet de l'acteur", example = "Admin Principal")
    private String acteurNomComplet;

    @Schema(description = "Rôles de l'acteur au moment de l'action")
    private String acteurRoles;

    // Quand
    @Schema(description = "Date et heure de l'action", example = "2025-01-15T10:30:00")
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
    private LocalDateTime dateAction;

    // Quoi
    @Schema(description = "Type d'action effectuée", example = "USER_CREATE")
    private TypeActionAudit typeAction;

    @Schema(description = "Type de ressource affectée", example = "USER")
    private String ressourceType;

    @Schema(description = "ID de la ressource affectée", example = "a1b2c3d4-e5f6-7890-1234-567890abcdef")
    private String ressourceId;

    @Schema(description = "Nom/Identifiant de la ressource", example = "jdupont")
    private String ressourceName;

    // Où
    @Schema(description = "Nom du Realm", example = "btpxpress")
    private String realmName;

    @Schema(description = "Adresse IP de l'acteur", example = "192.168.1.100")
    private String ipAddress;

    @Schema(description = "User-Agent du client", example = "Mozilla/5.0...")
    private String userAgent;

    @Schema(description = "Localisation géographique", example = "Abidjan, Côte d'Ivoire")
    private String geolocation;

    // Comment
    @Schema(description = "Endpoint API appelé", example = "/api/users/create")
    private String apiEndpoint;

    @Schema(description = "Méthode HTTP", example = "POST")
    private String httpMethod;

    // Détails
    @Schema(description = "Description de l'action", example = "Création d'un nouvel utilisateur")
    private String description;

    @Schema(description = "Détails de l'action au format JSON")
    private String detailsJson;

    @Schema(description = "Ancienne valeur (avant modification)")
    private String oldValue;

    @Schema(description = "Nouvelle valeur (après modification)")
    private String newValue;

    @Schema(description = "Différences entre ancienne et nouvelle valeur")
    private String diff;

    // Résultat
    @Schema(description = "Succès de l'opération", example = "true")
    private Boolean success;

    @Schema(description = "Code d'erreur (si échec)", example = "USER_ALREADY_EXISTS")
    private String errorCode;

    @Schema(description = "Message d'erreur (si échec)")
    private String errorMessage;

    @Schema(description = "Trace d'erreur complète (si échec)")
    private String stackTrace;

    // Métadonnées
    @Schema(description = "Durée d'exécution en millisecondes", example = "145")
    private Long executionTimeMs;

    @Schema(description = "ID de session/transaction", example = "sess_abc123")
    private String sessionId;

    @Schema(description = "ID de corrélation (pour tracer requêtes liées)", example = "corr_xyz789")
    private String correlationId;

    @Schema(description = "Raison de l'action", example = "Demande du manager")
    private String raison;

    @Schema(description = "Commentaires administratifs", example = "Promotion suite à évaluation annuelle")
    private String commentaires;

    @Schema(description = "Métadonnées supplémentaires")
    private Map<String, String> metadata;

    // Flags
    @Schema(description = "Indique si l'action est critique", example = "false")
    private Boolean critique;

    @Schema(description = "Indique si l'action nécessite une alerte", example = "false")
    private Boolean requiresAlert;

    @Schema(description = "Indique si l'action a été notifiée", example = "true")
    private Boolean notified;

    /**
     * Détermine si l'action a réussi
     * @return true si success = true
     */
    public boolean isSuccessful() {
        return Boolean.TRUE.equals(success);
    }

    /**
     * Détermine si l'action a échoué
     * @return true si success = false
     */
    public boolean isFailed() {
        return Boolean.FALSE.equals(success);
    }

    /**
     * Détermine si l'action est critique
     * @return true si critique = true ou si typeAction est critique
     */
    public boolean isCritique() {
        return Boolean.TRUE.equals(critique) || (typeAction != null && typeAction.isCritical());
    }

    /**
     * Retourne un résumé court de l'action
     * @return résumé
     */
    public String getSummary() {
        return String.format("%s: %s effectué par %s sur %s %s",
            dateAction,
            typeAction != null ? typeAction.getLibelle() : "Action inconnue",
            acteurUsername != null ? acteurUsername : "Inconnu",
            ressourceType != null ? ressourceType : "Ressource",
            ressourceName != null ? ressourceName : ressourceId
        );
    }
}
