// Package audit fournit le journal d'audit de ProxmoxPanel.
// Toutes les actions sensibles (connexion, mises à jour, modifications config) y sont tracées.
package audit

import (
	"database/sql"
	"encoding/json"
	"time"
)

// Entry représente une entrée dans le journal d'audit.
type Entry struct {
	ID        int64     `json:"id"`
	UserID    *int64    `json:"user_id,omitempty"`
	Username  string    `json:"username"`
	Action    string    `json:"action"`
	Resource  string    `json:"resource,omitempty"`
	Details   string    `json:"details,omitempty"`
	IP        string    `json:"ip,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

// Logger est le service d'audit.
type Logger struct {
	db *sql.DB
}

// New crée un nouveau Logger d'audit.
func New(db *sql.DB) *Logger {
	return &Logger{db: db}
}

// Log enregistre une action dans le journal d'audit.
func (l *Logger) Log(userID *int64, username, action, resource string, details any, ip string) {
	var detailsStr string
	if details != nil {
		if s, ok := details.(string); ok {
			detailsStr = s
		} else if data, err := json.Marshal(details); err == nil {
			detailsStr = string(data)
		}
	}

	// Insertion non bloquante — on ignore les erreurs pour ne pas perturber le flux principal
	l.db.Exec(`
		INSERT INTO audit_log (user_id, username, action, resource, details, ip, created_at)
		VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
	`, userID, username, action, resource, detailsStr, ip)
}

// GetEntries retourne les dernières entrées du journal, paginées.
func (l *Logger) GetEntries(limit, offset int) ([]Entry, error) {
	rows, err := l.db.Query(`
		SELECT id, user_id, username, action, resource, details, ip, created_at
		FROM audit_log
		ORDER BY created_at DESC
		LIMIT ? OFFSET ?
	`, limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var entries []Entry
	for rows.Next() {
		var e Entry
		var userID sql.NullInt64
		var resource, details, ip sql.NullString
		if err := rows.Scan(&e.ID, &userID, &e.Username, &e.Action, &resource, &details, &ip, &e.CreatedAt); err != nil {
			continue
		}
		if userID.Valid {
			e.UserID = &userID.Int64
		}
		e.Resource = resource.String
		e.Details = details.String
		e.IP = ip.String
		entries = append(entries, e)
	}
	return entries, rows.Err()
}
