package workers

import (
	"context"
	"testing"

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

func setupTestDB(t *testing.T) *gorm.DB {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	if err != nil {
		t.Fatalf("Failed to open test database: %v", err)
	}

	// Créer la table analytics_events
	if err := db.Exec(`
		CREATE TABLE analytics_events (
			id TEXT PRIMARY KEY,
			event_name TEXT NOT NULL,
			user_id TEXT,
			payload TEXT NOT NULL,
			created_at DATETIME NOT NULL
		)
	`).Error; err != nil {
		t.Fatalf("Failed to create test table: %v", err)
	}

	return db
}

func TestAnalyticsJob_Execute(t *testing.T) {
	logger := zap.NewNop()
	ctx := context.Background()
	db := setupTestDB(t)

	// Test 1: Enregistrement d'événement avec userID
	t.Run("Record event with user ID", func(t *testing.T) {
		userID := uuid.New()
		payload := map[string]interface{}{
			"action":   "track_play",
			"track_id": uuid.New().String(),
		}

		job := NewAnalyticsEventJob("track_play", &userID, payload)

		err := job.Execute(ctx, db, logger)
		if err != nil {
			t.Fatalf("Expected no error, got: %v", err)
		}

		// Vérifier que l'événement a été enregistré
		var event AnalyticsEvent
		if err := db.First(&event, "event_name = ?", "track_play").Error; err != nil {
			t.Fatalf("Failed to find recorded event: %v", err)
		}

		if event.EventName != "track_play" {
			t.Errorf("Expected event_name 'track_play', got '%s'", event.EventName)
		}
		if event.UserID == nil || *event.UserID != userID {
			t.Errorf("Expected user_id %s, got %v", userID, event.UserID)
		}
	})

	// Test 2: Enregistrement d'événement anonyme (sans userID)
	t.Run("Record anonymous event", func(t *testing.T) {
		payload := map[string]interface{}{
			"action": "page_view",
			"path":   "/tracks",
		}

		job := NewAnalyticsEventJob("page_view", nil, payload)

		err := job.Execute(ctx, db, logger)
		if err != nil {
			t.Fatalf("Expected no error, got: %v", err)
		}

		// Vérifier que l'événement a été enregistré
		var event AnalyticsEvent
		if err := db.First(&event, "event_name = ?", "page_view").Error; err != nil {
			t.Fatalf("Failed to find recorded event: %v", err)
		}

		if event.UserID != nil {
			t.Errorf("Expected nil user_id for anonymous event, got %v", event.UserID)
		}
	})

	// Test 3: Événement sans nom
	t.Run("Fail when event name is empty", func(t *testing.T) {
		job := NewAnalyticsEventJob("", nil, nil)

		err := job.Execute(ctx, db, logger)
		if err == nil {
			t.Fatal("Expected error for empty event name, got nil")
		}
	})
}

func TestNewAnalyticsJob(t *testing.T) {
	t.Run("Create job with all fields", func(t *testing.T) {
		userID := uuid.New()
		payload := map[string]interface{}{
			"key": "value",
		}

		job := NewAnalyticsEventJob("test_event", &userID, payload)

		if job.EventName != "test_event" {
			t.Errorf("Expected EventName 'test_event', got '%s'", job.EventName)
		}
		if job.UserID == nil || *job.UserID != userID {
			t.Errorf("Expected UserID %s, got %v", userID, job.UserID)
		}
		if job.Payload["key"] != "value" {
			t.Errorf("Expected payload key 'value', got '%v'", job.Payload["key"])
		}
	})

	t.Run("Create job with nil payload", func(t *testing.T) {
		job := NewAnalyticsEventJob("test_event", nil, nil)

		if job.Payload == nil {
			t.Fatal("Expected non-nil payload map, got nil")
		}
		if len(job.Payload) != 0 {
			t.Errorf("Expected empty payload map, got %d items", len(job.Payload))
		}
	})
}
