package cache

import (
	"context"
	"errors"
	"strings"
	"testing"
	"time"
)

func TestConsumeFixedWindowFailsClosedWithoutRedis(t *testing.T) {
	_, err := (*Redis)(nil).ConsumeFixedWindow(context.Background(), time.Minute, []FixedWindowRule{{Key: "rate:{external-login}:system", Limit: 300}})
	if !errors.Is(err, ErrRedisUnavailable) {
		t.Fatalf("error = %v, want ErrRedisUnavailable", err)
	}
}

func TestFixedWindowLuaConsumesAllKeysWithoutRenewingExistingTTL(t *testing.T) {
	// These source-level invariants protect the security semantics even when unit
	// tests run without a Redis daemon: all keys increment before the one final
	// return, and PEXPIRE remains inside count==1 so rejected requests never slide TTL.
	if strings.Count(fixedWindowScript, `redis.call("INCR"`) != 1 {
		t.Fatalf("fixed-window script must increment through one loop: %s", fixedWindowScript)
	}
	if !strings.Contains(fixedWindowScript, `if count == 1 then`) || !strings.Contains(fixedWindowScript, `redis.call("PEXPIRE"`) {
		t.Fatal("fixed-window script must assign expiry only on first increment")
	}
	if strings.Count(fixedWindowScript, "return {") != 1 {
		t.Fatal("fixed-window script must not return early before consuming all keys")
	}
	if strings.Index(fixedWindowScript, `redis.call("INCR"`) > strings.Index(fixedWindowScript, `if count > limit then`) {
		t.Fatal("fixed-window script must increment before deciding")
	}
}
