package router

import (
	"net/http"
	"sync"

	"github.com/atlasos/calypso/internal/common/config"
	"github.com/atlasos/calypso/internal/common/logger"
	"github.com/gin-gonic/gin"
	"golang.org/x/time/rate"
)

// rateLimiter manages rate limiting per IP address
type rateLimiter struct {
	limiters map[string]*rate.Limiter
	mu       sync.RWMutex
	config   config.RateLimitConfig
	logger   *logger.Logger
}

// newRateLimiter creates a new rate limiter
func newRateLimiter(cfg config.RateLimitConfig, log *logger.Logger) *rateLimiter {
	return &rateLimiter{
		limiters: make(map[string]*rate.Limiter),
		config:   cfg,
		logger:   log,
	}
}

// getLimiter returns a rate limiter for the given IP address
func (rl *rateLimiter) getLimiter(ip string) *rate.Limiter {
	rl.mu.RLock()
	limiter, exists := rl.limiters[ip]
	rl.mu.RUnlock()

	if exists {
		return limiter
	}

	// Create new limiter for this IP
	rl.mu.Lock()
	defer rl.mu.Unlock()

	// Double-check after acquiring write lock
	if limiter, exists := rl.limiters[ip]; exists {
		return limiter
	}

	// Create limiter with configured rate
	limiter = rate.NewLimiter(rate.Limit(rl.config.RequestsPerSecond), rl.config.BurstSize)
	rl.limiters[ip] = limiter

	return limiter
}

// rateLimitMiddleware creates rate limiting middleware
func rateLimitMiddleware(cfg *config.Config, log *logger.Logger) gin.HandlerFunc {
	if !cfg.Security.RateLimit.Enabled {
		// Rate limiting disabled, return no-op middleware
		return func(c *gin.Context) {
			c.Next()
		}
	}

	limiter := newRateLimiter(cfg.Security.RateLimit, log)

	return func(c *gin.Context) {
		ip := c.ClientIP()
		limiter := limiter.getLimiter(ip)

		if !limiter.Allow() {
			log.Warn("Rate limit exceeded", "ip", ip, "path", c.Request.URL.Path)
			c.JSON(http.StatusTooManyRequests, gin.H{
				"error": "rate limit exceeded",
			})
			c.Abort()
			return
		}

		c.Next()
	}
}

