package testutils

import (
	"sync"
	"testing"
)

var (
	parallelLock sync.Mutex
)

// SetupParallelTest configure un test pour exécution parallèle (T0048)
func SetupParallelTest(t *testing.T) {
	t.Parallel()

	// Acquérir un lock si ressources partagées
	// parallelLock.Lock()
	// t.Cleanup(func() { parallelLock.Unlock() })
}

// RunParallelTests exécute plusieurs tests en parallèle (T0048)
// Note: The sub-tests created by t.Run() already call t.Parallel(), so testFuncs
// should NOT call SetupParallelTest() or t.Parallel() themselves to avoid "t.Parallel called multiple times" panic
// The parent test must wait for all sub-tests to complete
func RunParallelTests(t *testing.T, testFuncs map[string]func(*testing.T)) {
	// Use t.Run() which automatically waits for all sub-tests to complete
	// Each sub-test calls t.Parallel() to run in parallel
	for name, fn := range testFuncs {
		t.Run(name, func(t *testing.T) {
			t.Parallel()
			fn(t)
		})
	}
	// t.Run() blocks until all sub-tests complete, so we don't need WaitGroup
}

// WithLock exécute une fonction avec un lock partagé (T0048)
func WithLock(fn func()) {
	parallelLock.Lock()
	defer parallelLock.Unlock()
	fn()
}

// TestLockManager gère les locks pour les tests parallèles (T0048)
type TestLockManager struct {
	locks map[string]*sync.Mutex
	mu    sync.RWMutex
}

// NewTestLockManager crée un nouveau gestionnaire de locks (T0048)
func NewTestLockManager() *TestLockManager {
	return &TestLockManager{
		locks: make(map[string]*sync.Mutex),
	}
}

// Lock acquiert un lock nommé (T0048)
func (tm *TestLockManager) Lock(name string) func() {
	tm.mu.Lock()
	lock, exists := tm.locks[name]
	if !exists {
		lock = &sync.Mutex{}
		tm.locks[name] = lock
	}
	tm.mu.Unlock()

	lock.Lock()
	return func() {
		lock.Unlock()
	}
}

// Example usage:
/*
func TestParallel(t *testing.T) {
	testFuncs := map[string]func(*testing.T){
		"test1": func(t *testing.T) {
			SetupParallelTest(t)
			// Test code
		},
		"test2": func(t *testing.T) {
			SetupParallelTest(t)
			// Test code
		},
	}

	RunParallelTests(t, testFuncs)
}

func TestWithSharedResource(t *testing.T) {
	t.Parallel()

	WithLock(func() {
		// Code qui nécessite un lock
	})
}

func TestWithNamedLock(t *testing.T) {
	t.Parallel()

	lockManager := NewTestLockManager()
	unlock := lockManager.Lock("resource1")
	defer unlock()

	// Code qui nécessite un lock nommé
}
*/
