package auth

import (
	"testing"
	"time"
)

func TestRateLimiterExhaustionAndRefill(t *testing.T) {
	rl := NewRateLimiter(10, 15*time.Minute)
	now := time.Date(2026, 6, 12, 12, 0, 0, 0, time.UTC)
	rl.now = func() time.Time { return now }

	for i := 0; i < 10; i++ {
		if !rl.Allow("ip|a@b.c") {
			t.Fatalf("attempt %d should be allowed", i+1)
		}
	}
	if rl.Allow("ip|a@b.c") {
		t.Fatal("11th attempt must be blocked")
	}

	// Other keys are unaffected.
	if !rl.Allow("ip|other@b.c") {
		t.Fatal("different key must have its own bucket")
	}

	// After 1.5 minutes one token has refilled (10 per 15 min).
	now = now.Add(90 * time.Second)
	if !rl.Allow("ip|a@b.c") {
		t.Fatal("one attempt should have refilled")
	}
	if rl.Allow("ip|a@b.c") {
		t.Fatal("bucket must be empty again")
	}

	// A full window refills completely, capped at capacity.
	now = now.Add(time.Hour)
	for i := 0; i < 10; i++ {
		if !rl.Allow("ip|a@b.c") {
			t.Fatalf("post-refill attempt %d should be allowed", i+1)
		}
	}
	if rl.Allow("ip|a@b.c") {
		t.Fatal("refill must cap at capacity")
	}
}

func TestRateLimiterGC(t *testing.T) {
	rl := NewRateLimiter(10, 15*time.Minute)
	now := time.Date(2026, 6, 12, 12, 0, 0, 0, time.UTC)
	rl.now = func() time.Time { return now }

	rl.Allow("stale")
	now = now.Add(16 * time.Minute)
	rl.Allow("fresh") // triggers gc
	rl.mu.Lock()
	_, staleExists := rl.buckets["stale"]
	rl.mu.Unlock()
	if staleExists {
		t.Fatal("idle bucket should have been swept")
	}
}
