package workers

import (
	"context"
	"os"
	"path/filepath"
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap/zaptest"
	"gorm.io/driver/sqlite"
	"gorm.io/gorm"

	"veza-backend-api/internal/models"
	"veza-backend-api/internal/services"
)

func setupTestPlaybackRetentionWorker(t *testing.T) (*gorm.DB, *PlaybackRetentionWorker, func()) {
	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	require.NoError(t, err)

	db.Exec("PRAGMA foreign_keys = ON")

	err = db.AutoMigrate(&models.User{}, &models.Track{}, &models.PlaybackAnalytics{})
	require.NoError(t, err)

	logger := zaptest.NewLogger(t)

	// Créer un répertoire temporaire pour les archives
	tempDir := filepath.Join(os.TempDir(), "playback_retention_worker_test_"+t.Name())
	require.NoError(t, os.MkdirAll(tempDir, 0755))

	retentionService := services.NewPlaybackRetentionPolicyService(db, tempDir, logger)
	worker := NewPlaybackRetentionWorker(db, retentionService, logger, 1*time.Hour)

	cleanup := func() {
		os.RemoveAll(tempDir)
	}

	return db, worker, cleanup
}

func TestNewPlaybackRetentionWorker(t *testing.T) {
	db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	logger := zaptest.NewLogger(t)
	retentionService := services.NewPlaybackRetentionPolicyService(db, "", logger)

	worker := NewPlaybackRetentionWorker(db, retentionService, logger, 24*time.Hour)

	assert.NotNil(t, worker)
	assert.Equal(t, db, worker.db)
	assert.Equal(t, retentionService, worker.retentionService)
	assert.Equal(t, 24*time.Hour, worker.interval)
	assert.False(t, worker.running)
}

func TestNewPlaybackRetentionWorker_DefaultInterval(t *testing.T) {
	db, _ := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
	logger := zaptest.NewLogger(t)
	retentionService := services.NewPlaybackRetentionPolicyService(db, "", logger)

	worker := NewPlaybackRetentionWorker(db, retentionService, logger, 0)

	assert.Equal(t, 24*time.Hour, worker.interval)
}

func TestPlaybackRetentionWorker_SetPolicy(t *testing.T) {
	_, worker, cleanup := setupTestPlaybackRetentionWorker(t)
	defer cleanup()

	customPolicy := &services.RetentionPolicy{
		ArchiveAfter: 60 * 24 * time.Hour,
		DeleteAfter:  180 * 24 * time.Hour,
		Compress:     true,
	}

	worker.SetPolicy(customPolicy)

	assert.Equal(t, customPolicy, worker.policy)
}

func TestPlaybackRetentionWorker_SetPolicy_Nil(t *testing.T) {
	_, worker, cleanup := setupTestPlaybackRetentionWorker(t)
	defer cleanup()

	originalPolicy := worker.policy
	worker.SetPolicy(nil)

	// La politique ne devrait pas changer si nil est passé
	assert.Equal(t, originalPolicy, worker.policy)
}

func TestPlaybackRetentionWorker_IsRunning(t *testing.T) {
	_, worker, cleanup := setupTestPlaybackRetentionWorker(t)
	defer cleanup()

	assert.False(t, worker.IsRunning())
}

func TestPlaybackRetentionWorker_Start_Stop(t *testing.T) {
	_, worker, cleanup := setupTestPlaybackRetentionWorker(t)
	defer cleanup()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Démarrer le worker dans une goroutine
	go worker.Start(ctx)

	// Attendre un peu pour que le worker démarre
	time.Sleep(100 * time.Millisecond)

	// Vérifier que le worker est en cours d'exécution
	// Note: Le worker peut ne pas être marqué comme running immédiatement
	// car Start() démarre une goroutine qui peut prendre du temps

	// Arrêter le worker
	worker.Stop()

	// Attendre un peu pour que le worker s'arrête
	time.Sleep(100 * time.Millisecond)
}

func TestPlaybackRetentionWorker_Start_AlreadyRunning(t *testing.T) {
	_, worker, cleanup := setupTestPlaybackRetentionWorker(t)
	defer cleanup()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	// Démarrer le worker
	go worker.Start(ctx)
	time.Sleep(50 * time.Millisecond)

	// Essayer de démarrer à nouveau (ne devrait rien faire)
	worker.Start(ctx)

	// Nettoyer
	cancel()
	worker.Stop()
	time.Sleep(50 * time.Millisecond)
}
