package middleware

import (
	"fmt"
	"time"

	"gitee.com/xuyiping_admin/pkg/apierr"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"github.com/gin-gonic/gin"
	limit "github.com/yangxikun/gin-limit-by-key"
	"golang.org/x/time/rate"
)

// RateLimit limit rate by client ip
// limit 10 qps/client_ip and permit bursts of at most 10 tokens, and the limiter live time duration is 3 minutes
// handle exceed rate limit request
func RateLimit(opts ...*RateLimitOption) gin.HandlerFunc {
	var opt *RateLimitOption
	if len(opts) == 0 {
		opt = defaultRateLimitOption
	} else {
		opt = opts[0]
	}

	return limit.NewRateLimiter(func(c *gin.Context) string {
		return fmt.Sprintf("%s-%s", c.ClientIP(), authorization(c))
	}, func(c *gin.Context) (*rate.Limiter, time.Duration) {
		return rate.NewLimiter(rate.Every(opt.Interval), opt.Tokens), opt.LiveTime
	}, func(c *gin.Context) {
		apierr.AbortBadRequest(c, 429, xerr.Customf("request too many %s", c.ClientIP()))
	})
}

type RateLimitOption struct {
	Interval time.Duration
	Tokens   int
	LiveTime time.Duration
}

var defaultRateLimitOption = &RateLimitOption{
	Interval: 100 * time.Millisecond,
	Tokens:   10,
	LiveTime: 3 * time.Minute,
}

var testRateLimitOption = &RateLimitOption{
	Interval: 10 * time.Millisecond,
	Tokens:   1000,
	LiveTime: 1 * time.Minute,
}

func RateLimitOptionLow() *RateLimitOption {
	return &RateLimitOption{
		Interval: 1 * time.Second,
		Tokens:   10,
		LiveTime: 3 * time.Minute,
	}
}