package workers

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"github.com/google/uuid"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

// AnalyticsEventJob représente un job d'enregistrement d'événement analytics générique
type AnalyticsEventJob struct {
	EventName string                 // Nom de l'événement (ex: "track_play", "user_login", "file_upload")
	UserID    *uuid.UUID             // ID de l'utilisateur (nullable pour événements anonymes)
	Payload   map[string]interface{} // Données additionnelles de l'événement
}

// NewAnalyticsEventJob crée un nouveau job d'analytics générique
func NewAnalyticsEventJob(eventName string, userID *uuid.UUID, payload map[string]interface{}) *AnalyticsEventJob {
	if payload == nil {
		payload = make(map[string]interface{})
	}
	return &AnalyticsEventJob{
		EventName: eventName,
		UserID:    userID,
		Payload:   payload,
	}
}

// AnalyticsEvent représente un événement analytics en base de données
type AnalyticsEvent struct {
	ID        uuid.UUID  `gorm:"type:uuid;primaryKey"`
	EventName string     `gorm:"not null;index:idx_analytics_events_name"`
	UserID    *uuid.UUID `gorm:"type:uuid;index:idx_analytics_events_user_id"`
	Payload   string     `gorm:"type:jsonb"` // Stocké en JSONB pour PostgreSQL
	CreatedAt time.Time  `gorm:"autoCreateTime;index:idx_analytics_events_created_at"`
}

// TableName définit le nom de la table pour GORM
func (AnalyticsEvent) TableName() string {
	return "analytics_events"
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (a *AnalyticsEvent) BeforeCreate(tx *gorm.DB) error {
	if a.ID == uuid.Nil {
		a.ID = uuid.New()
	}
	return nil
}

// Execute exécute le job d'analytics générique
func (j *AnalyticsEventJob) Execute(ctx context.Context, db *gorm.DB, logger *zap.Logger) error {
	// Valider le nom de l'événement
	if j.EventName == "" {
		return fmt.Errorf("event name is required")
	}

	// Sérialiser le payload en JSON
	payloadJSON, err := json.Marshal(j.Payload)
	if err != nil {
		return fmt.Errorf("failed to marshal payload: %w", err)
	}

	// Créer l'événement analytics
	event := AnalyticsEvent{
		EventName: j.EventName,
		UserID:    j.UserID,
		Payload:   string(payloadJSON),
		CreatedAt: time.Now(),
	}

	// Enregistrer en base de données
	if err := db.WithContext(ctx).Create(&event).Error; err != nil {
		return fmt.Errorf("failed to save analytics event: %w", err)
	}

	logger.Info("Analytics event recorded",
		zap.String("event_name", j.EventName),
		zap.String("event_id", event.ID.String()),
		zap.Any("user_id", j.UserID),
		zap.Int("payload_size", len(payloadJSON)),
	)

	return nil
}
