package ratelimit_test

import (
	"testing"
	"time"

	"scrabble/gateway/internal/config"
	"scrabble/gateway/internal/ratelimit"
)

func TestAllowEnforcesBurst(t *testing.T) {
	l := ratelimit.New()
	p := ratelimit.PerMinute(60, 3) // 1/s, burst 3
	allowed := 0
	for i := 0; i < 5; i++ {
		if l.Allow("ip:1.2.3.4", p) {
			allowed++
		}
	}
	if allowed != 3 {
		t.Fatalf("allowed %d of 5, want 3 (burst)", allowed)
	}
}

func TestAllowIsolatesKeys(t *testing.T) {
	l := ratelimit.New()
	p := ratelimit.PerMinute(60, 1)
	if !l.Allow("user:a", p) {
		t.Fatal("first key should be allowed")
	}
	if !l.Allow("user:b", p) {
		t.Fatal("a different key must have its own bucket")
	}
	if l.Allow("user:a", p) {
		t.Fatal("the first key's bucket should now be empty")
	}
}

func TestPerWindow(t *testing.T) {
	// 5 events per 10 minutes, burst 2: the third immediate call is denied.
	p := ratelimit.Per(5, 10*time.Minute, 2)
	l := ratelimit.New()
	got := []bool{l.Allow("email:x", p), l.Allow("email:x", p), l.Allow("email:x", p)}
	if !got[0] || !got[1] || got[2] {
		t.Fatalf("per-window burst = %v, want [true true false]", got)
	}
}

// TestEmailBurstAllowsHonestLoginFlow guards the default email-code burst against being
// tightened back below the honest login sequence: requesting a code, submitting one wrong
// code, then the correct one are three immediate email-class events from one IP, and all
// must pass. A burst of 2 denied the correct-code login, which the client mis-read as going
// offline and could not recover from on the session-less login screen. This is defence in
// depth over the backend's own per-code attempt cap and code TTL.
func TestEmailBurstAllowsHonestLoginFlow(t *testing.T) {
	rl := config.DefaultRateLimit()
	p := ratelimit.Per(rl.EmailPer10Min, 10*time.Minute, rl.EmailBurst)
	l := ratelimit.New()
	for i, want := range []bool{true, true, true} { // request code, wrong code, right code
		if got := l.Allow("email:198.51.100.7", p); got != want {
			t.Fatalf("honest email event %d allowed = %v, want %v", i+1, got, want)
		}
	}
}
