package testutils

import (
	"testing"
	"time"
)

func TestStartTimer(t *testing.T) {
	timer := StartTimer(t)
	if timer == nil {
		t.Fatal("Expected timer to be non-nil")
	}
	if timer.start.IsZero() {
		t.Error("Expected timer start time to be set")
	}
	if timer.t != t {
		t.Error("Expected timer to reference the test")
	}
	if timer.name != t.Name() {
		t.Errorf("Expected timer name to be '%s', got '%s'", t.Name(), timer.name)
	}
}

func TestStartNamedTimer(t *testing.T) {
	customName := "custom-test-name"
	timer := StartNamedTimer(t, customName)
	if timer == nil {
		t.Fatal("Expected timer to be non-nil")
	}
	if timer.name != customName {
		t.Errorf("Expected timer name to be '%s', got '%s'", customName, timer.name)
	}
}

func TestTimer_Stop(t *testing.T) {
	timer := StartTimer(t)

	// Attendre un peu pour avoir une durée mesurable
	time.Sleep(10 * time.Millisecond)

	duration := timer.Stop()
	if duration < 10*time.Millisecond {
		t.Errorf("Expected duration to be at least 10ms, got %v", duration)
	}
	if duration > 100*time.Millisecond {
		t.Errorf("Expected duration to be less than 100ms, got %v", duration)
	}
}

func TestTimer_WarnIfSlow_SlowTest(t *testing.T) {
	timer := StartTimer(t)
	threshold := 50 * time.Millisecond

	// Faire un test "lent" (dépassant le seuil)
	time.Sleep(100 * time.Millisecond)

	duration := timer.WarnIfSlow(threshold)
	if duration < threshold {
		t.Errorf("Expected duration to be greater than threshold %v, got %v", threshold, duration)
	}
}

func TestTimer_WarnIfSlow_FastTest(t *testing.T) {
	timer := StartTimer(t)
	threshold := 1 * time.Second

	// Faire un test "rapide" (sous le seuil)
	time.Sleep(10 * time.Millisecond)

	duration := timer.WarnIfSlow(threshold)
	if duration >= threshold {
		t.Errorf("Expected duration to be less than threshold %v, got %v", threshold, duration)
	}
}

func TestTimer_Elapsed(t *testing.T) {
	timer := StartTimer(t)

	// Attendre un peu
	time.Sleep(20 * time.Millisecond)

	elapsed := timer.Elapsed()
	if elapsed < 20*time.Millisecond {
		t.Errorf("Expected elapsed time to be at least 20ms, got %v", elapsed)
	}
	if elapsed > 100*time.Millisecond {
		t.Errorf("Expected elapsed time to be less than 100ms, got %v", elapsed)
	}

	// Vérifier que Elapsed ne réinitialise pas le timer
	time.Sleep(10 * time.Millisecond)
	elapsed2 := timer.Elapsed()
	if elapsed2 <= elapsed {
		t.Errorf("Expected elapsed2 (%v) to be greater than elapsed (%v)", elapsed2, elapsed)
	}
}

func TestTimer_Reset(t *testing.T) {
	timer := StartTimer(t)

	// Attendre un peu
	time.Sleep(20 * time.Millisecond)
	elapsed1 := timer.Elapsed()

	if elapsed1 < 20*time.Millisecond {
		t.Errorf("Expected elapsed1 to be at least 20ms, got %v", elapsed1)
	}

	// Réinitialiser le timer
	timer.Reset()

	// Attendre un peu moins
	time.Sleep(10 * time.Millisecond)
	elapsed2 := timer.Elapsed()

	// elapsed2 devrait être proche de 10ms (pas 30ms)
	if elapsed2 >= elapsed1 {
		t.Errorf("Expected elapsed2 (%v) to be less than elapsed1 (%v) after reset", elapsed2, elapsed1)
	}
	if elapsed2 > 50*time.Millisecond {
		t.Errorf("Expected elapsed2 to be less than 50ms after reset, got %v", elapsed2)
	}
}

func TestTimer_IntegrationExample(t *testing.T) {
	// Exemple d'utilisation complète comme dans la documentation
	timer := StartTimer(t)
	defer timer.WarnIfSlow(5 * time.Second)

	// Simuler une opération de test
	time.Sleep(10 * time.Millisecond)

	duration := timer.Stop()
	if duration < 10*time.Millisecond {
		t.Errorf("Expected duration to be at least 10ms, got %v", duration)
	}
}

func TestTimer_MultipleOperations(t *testing.T) {
	timer := StartTimer(t)

	// Première opération
	time.Sleep(10 * time.Millisecond)
	elapsed1 := timer.Elapsed()

	// Réinitialiser pour la deuxième opération
	timer.Reset()

	// Deuxième opération
	time.Sleep(15 * time.Millisecond)
	elapsed2 := timer.Elapsed()

	if elapsed1 < 10*time.Millisecond {
		t.Errorf("Expected elapsed1 to be at least 10ms, got %v", elapsed1)
	}
	if elapsed2 < 15*time.Millisecond {
		t.Errorf("Expected elapsed2 to be at least 15ms, got %v", elapsed2)
	}
	// After reset, elapsed2 measures time since reset (15ms), elapsed1 measures time since start (10ms)
	// elapsed2 should be greater than elapsed1 because it includes the reset time + 15ms sleep
	// The test logic was incorrect - elapsed2 should be greater than elapsed1, not less
	if elapsed2 <= elapsed1 {
		t.Errorf("Expected elapsed2 (%v) to be greater than elapsed1 (%v) after reset and additional sleep", elapsed2, elapsed1)
	}
}

func TestTimer_Stop_ReturnsCorrectDuration(t *testing.T) {
	timer := StartTimer(t)

	sleepDuration := 25 * time.Millisecond
	time.Sleep(sleepDuration)

	duration := timer.Stop()

	// Vérifier que la durée est raisonnable (au moins le temps de sleep)
	if duration < sleepDuration {
		t.Errorf("Expected duration to be at least %v, got %v", sleepDuration, duration)
	}
	// Vérifier qu'elle n'est pas trop grande (tolérance de 50ms)
	if duration > sleepDuration+50*time.Millisecond {
		t.Errorf("Expected duration to be close to %v, got %v", sleepDuration, duration)
	}
}
