package storage

import (
	"context"
	"fmt"
	"local/dndex/config"
	"local/dndex/storage/entity"
	"sync"

	"golang.org/x/time/rate"
)

type RateLimitedGraph struct {
	g        Graph
	rps      int
	limiters *sync.Map
}

func NewRateLimitedGraph(path ...string) RateLimitedGraph {
	return RateLimitedGraph{
		g:        NewGraph(path...),
		rps:      config.New().RPS,
		limiters: &sync.Map{},
	}
}

func (rlg RateLimitedGraph) limit(ctx context.Context, namespace string) error {
	limiter, ok := rlg.limiters.Load(namespace)
	if !ok {
		config := config.New()
		limiter = rate.NewLimiter(rate.Limit(config.RPS), config.RPS)
		rlg.limiters.Store(namespace, limiter)
	}
	limit, ok := limiter.(*rate.Limiter)
	if !ok {
		return fmt.Errorf("rate limiter is of type %T", limiter)
	}
	return limit.Wait(ctx)
}

func (rlg RateLimitedGraph) Delete(ctx context.Context, namespace string, filter interface{}) error {
	return rlg.g.Delete(ctx, namespace, filter)
}

func (rlg RateLimitedGraph) Insert(ctx context.Context, namespace string, one entity.One) error {
	return rlg.g.Insert(ctx, namespace, one)
}

func (rlg RateLimitedGraph) Get(ctx context.Context, namespace, id string) (entity.One, error) {
	return rlg.g.Get(ctx, namespace, id)
}

func (rlg RateLimitedGraph) List(ctx context.Context, namespace string, from ...string) ([]entity.One, error) {
	return rlg.g.List(ctx, namespace, from...)
}

func (rlg RateLimitedGraph) ListCaseInsensitive(ctx context.Context, namespace string, from ...string) ([]entity.One, error) {
	return rlg.g.ListCaseInsensitive(ctx, namespace, from...)
}

func (rlg RateLimitedGraph) Search(ctx context.Context, namespace string, nameContains string) ([]entity.One, error) {
	return rlg.g.Search(ctx, namespace, nameContains)
}

func (rlg RateLimitedGraph) Update(ctx context.Context, namespace string, one, modify interface{}) error {
	return rlg.g.Update(ctx, namespace, one, modify)
}
