package testutils

import (
	"testing"

	"veza-backend-api/internal/models"

	"gorm.io/gorm"
)

func TestCleanupOptions(t *testing.T) {
	opts := CleanupOptions{
		Cascade:        true,
		UseTransaction: false,

		Tables: []string{"users", "tracks"},
	}

	if !opts.Cascade {
		t.Error("Expected Cascade to be true")
	}
	if opts.UseTransaction {
		t.Error("Expected UseTransaction to be false")
	}
	if len(opts.Tables) != 2 {
		t.Errorf("Expected 2 tables, got %d", len(opts.Tables))
	}
}

func TestCleanupDatabaseWithOptions_NoTransaction(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping database test in short mode")
	}

	db := SetupTestDB()

	// Créer quelques données de test
	user := &models.User{
		Username:     "testuser",
		Email:        "test@example.com",
		PasswordHash: "hash",
		Role:         "user",
	}
	db.Create(user)

	var count int64
	db.Model(&models.User{}).Count(&count)
	if count == 0 {
		t.Fatal("Failed to create test user")
	}

	// Nettoyer avec options
	opts := CleanupOptions{
		Cascade:         true,
		UseTransaction:  false,
		SkipForeignKeys: false,
	}

	err := CleanupDatabaseWithOptions(t, db, opts)
	if err != nil {
		t.Errorf("CleanupDatabaseWithOptions failed: %v", err)
	}

	// Vérifier que les données ont été nettoyées
	db.Model(&models.User{}).Count(&count)
	if count != 0 {
		t.Errorf("Expected 0 users after cleanup, got %d", count)
	}
}

func TestCleanupDatabaseWithOptions_WithTransaction(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping database test in short mode")
	}

	db := SetupTestDB()

	// Créer quelques données de test
	user := &models.User{
		Username:     "testuser",
		Email:        "test@example.com",
		PasswordHash: "hash",
		Role:         "user",
	}
	db.Create(user)

	var countBefore int64
	db.Model(&models.User{}).Count(&countBefore)
	if countBefore == 0 {
		t.Fatal("Failed to create test user")
	}

	// Nettoyer avec transaction (qui sera rollback)
	opts := CleanupOptions{
		Cascade:         true,
		UseTransaction:  true,
		SkipForeignKeys: false,
	}

	err := CleanupDatabaseWithOptions(t, db, opts)
	if err != nil {
		t.Errorf("CleanupDatabaseWithOptions failed: %v", err)
	}

	// Après rollback, les données devraient toujours exister
	var countAfter int64
	db.Model(&models.User{}).Count(&countAfter)
	if countAfter == 0 {
		t.Error("Expected data to still exist after transaction rollback")
	}
}

func TestCleanupDatabaseWithOptions_SpecificTables(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping database test in short mode")
	}

	db := SetupTestDB()

	// Créer un utilisateur
	user := &models.User{
		Username:     "testuser",
		Email:        "test@example.com",
		PasswordHash: "hash",
		Role:         "user",
	}
	db.Create(user)

	// Nettoyer uniquement la table users
	opts := CleanupOptions{
		Cascade:         true,
		UseTransaction:  false,
		SkipForeignKeys: false,
		Tables:          []string{"users"},
	}

	err := CleanupDatabaseWithOptions(t, db, opts)
	if err != nil {
		t.Errorf("CleanupDatabaseWithOptions failed: %v", err)
	}

	// Vérifier que les utilisateurs ont été nettoyés
	var count int64
	db.Model(&models.User{}).Count(&count)
	if count != 0 {
		t.Errorf("Expected 0 users after cleanup, got %d", count)
	}
}

func TestCleanupSpecificTables(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping database test in short mode")
	}

	db := SetupTestDB()

	// Créer un utilisateur
	user := &models.User{
		Username:     "testuser",
		Email:        "test@example.com",
		PasswordHash: "hash",
		Role:         "user",
	}
	db.Create(user)

	// Nettoyer uniquement users
	err := CleanupSpecificTables(t, db, []string{"users"})
	if err != nil {
		t.Errorf("CleanupSpecificTables failed: %v", err)
	}

	var count int64
	db.Model(&models.User{}).Count(&count)
	if count != 0 {
		t.Errorf("Expected 0 users after cleanup, got %d", count)
	}
}

func TestCleanupWithTransaction(t *testing.T) {
	if testing.Short() {
		t.Skip("Skipping database test in short mode")
	}

	db := SetupTestDB()

	// Créer un utilisateur
	user := &models.User{
		Username:     "testuser",
		Email:        "test@example.com",
		PasswordHash: "hash",
		Role:         "user",
	}
	db.Create(user)

	var countBefore int64
	db.Model(&models.User{}).Count(&countBefore)

	// Nettoyer avec transaction (qui sera rollback)
	err := CleanupWithTransaction(t, db, func(tx *gorm.DB) {
		tx.Exec("TRUNCATE TABLE users")
	})
	if err != nil {
		t.Errorf("CleanupWithTransaction failed: %v", err)
	}

	// Après rollback, les données devraient toujours exister
	var countAfter int64
	db.Model(&models.User{}).Count(&countAfter)
	if countAfter != countBefore {
		t.Errorf("Expected data to still exist after transaction rollback. Before: %d, After: %d", countBefore, countAfter)
	}
}

func TestRegisterCleanupHook(t *testing.T) {
	cleanupCalled := false

	RegisterCleanupHook(t, func() {
		cleanupCalled = true
	})

	// Le cleanup sera appelé automatiquement à la fin du test
	// On ne peut pas vraiment tester que ça fonctionne sans attendre la fin du test,
	// mais on peut au moins vérifier que la fonction ne panique pas
	if cleanupCalled {
		t.Error("Cleanup should not be called immediately")
	}
}

func TestGetDefaultTables(t *testing.T) {
	tables := getDefaultTables()

	if len(tables) == 0 {
		t.Error("Expected default tables list to not be empty")
	}

	// Vérifier quelques tables attendues
	expectedTables := []string{"users", "tracks", "playlists", "rooms"}
	for _, expected := range expectedTables {
		found := false
		for _, table := range tables {
			if table == expected {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Expected table %s to be in default tables list", expected)
		}
	}
}
