package ratelimit

import (
	"sort"
	"testing"

	"github.com/onsi/gomega"
	"golang.org/x/time/rate"

	"github.com/pingcap-inc/clinic/pkg/config"
)

var uris = []*config.LimitConfig{
	{
		URI:   "/grafana/*",
		Limit: 60,
		Burst: 20,
	},
	{
		URI:   "/clinic/api/*",
		Limit: 20,
		Burst: 5,
	},
	{
		URI:   "/kibana/*",
		Limit: 39,
		Burst: 9,
	},
	{
		URI:   "*",
		Limit: 13,
		Burst: 3,
	},
	{
		URI:   "/grafana/api/*",
		Limit: 40,
		Burst: 10,
	},
}

func Test_URIMatch(t *testing.T) {
	sort.Slice(uris, func(i, j int) bool {
		return len(uris[i].URI) > len(uris[j].URI)
	})

	g := gomega.NewWithT(t)

	limiter := newLimiter("/grafana/public/fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2/1234", uris)
	g.Expect(limiter.limiter.Limit()).To(gomega.Equal(rate.Limit(60)))
	g.Expect(limiter.limiter.Burst()).To(gomega.Equal(20))

	limiter = newLimiter("/grafana/api/datasources/proxy/1/api/v1/series/123123", uris)
	g.Expect(limiter.limiter.Limit()).To(gomega.Equal(rate.Limit(40)))
	g.Expect(limiter.limiter.Burst()).To(gomega.Equal(10))

	limiter = newLimiter("/kibana/public/fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2/1234", uris)
	g.Expect(limiter.limiter.Limit()).To(gomega.Equal(rate.Limit(39)))
	g.Expect(limiter.limiter.Burst()).To(gomega.Equal(9))

	limiter = newLimiter("/clinic/api/v1/upload/123123", uris)
	g.Expect(limiter.limiter.Limit()).To(gomega.Equal(rate.Limit(20)))
	g.Expect(limiter.limiter.Burst()).To(gomega.Equal(5))

	limiter = newLimiter("/api/v1/upload/3124", uris)
	g.Expect(limiter.limiter.Limit()).To(gomega.Equal(rate.Limit(13)))
	g.Expect(limiter.limiter.Burst()).To(gomega.Equal(3))
}

func Test_RateLimiter(t *testing.T) {
	sort.Slice(uris, func(i, j int) bool {
		return len(uris[i].URI) > len(uris[j].URI)
	})
	g := gomega.NewWithT(t)

	rateLimiter := NewRateLimiter(uris)

	limiter := rateLimiter.Get("/grafana/public/fonts/roboto/RxZJdnzeo3R5zSexge8UUVtXRa8TVwTICgirnJhmVJw.woff2/1234")

	for i := 0; i < 50; i++ {
		if i < 20 {
			g.Expect(limiter.Allow()).To(gomega.BeTrue())
		}

		if i > 30 {
			g.Expect(limiter.Allow()).To(gomega.BeFalse())
		}
	}
}
