package redis

import (
	"context"
	"fmt"
	"time"

	"github.com/redis/go-redis/v9"
)

// Allow performs a fixed-window rate check (api-design.md §12).
// Returns ok=false when the limit is exceeded. Works per key; window resets
// every duration. When rdb is nil (Redis disabled) it always allows.
func Allow(ctx context.Context, rdb *redis.Client, key string, limit int64, window time.Duration) (bool, error) {
	if rdb == nil || limit <= 0 {
		return true, nil
	}
	now := time.Now().Unix()
	windowKey := fmt.Sprintf("%s:%d", key, now/windowSeconds(window))

	// Enforce in Redis atomically (dev/prod); correctness here is good-enough
	// for rate limiting (not for financial truth).
	pipe := rdb.Pipeline()
	incr := pipe.Incr(ctx, windowKey)
	pipe.Expire(ctx, windowKey, window+window/10)
	if _, err := pipe.Exec(ctx); err != nil {
		return false, err
	}
	val := incr.Val()
	if val > limit {
		return false, nil
	}
	return true, nil
}

func windowSeconds(d time.Duration) int64 {
	s := int64(d / time.Second)
	if s < 1 {
		return 1
	}
	return s
}
