package api

import (
	"sync"
	"time"
)

type limiter struct {
	mu     sync.Mutex
	hits   map[string]*window
	limit  int
	window time.Duration
	lastGC time.Time
}

type window struct {
	count int
	start time.Time
}

func newLimiter(limit int, per time.Duration) *limiter {
	return &limiter{
		hits:   make(map[string]*window),
		limit:  limit,
		window: per,
		lastGC: time.Now(),
	}
}

func (l *limiter) allow(key string) bool {
	l.mu.Lock()
	defer l.mu.Unlock()

	now := time.Now()
	l.gc(now)

	w, ok := l.hits[key]
	if !ok || now.Sub(w.start) > l.window {
		l.hits[key] = &window{count: 1, start: now}
		return true
	}

	if w.count >= l.limit {
		return false
	}
	w.count++
	return true
}

func (l *limiter) gc(now time.Time) {
	if now.Sub(l.lastGC) < l.window {
		return
	}
	for key, w := range l.hits {
		if now.Sub(w.start) > l.window {
			delete(l.hits, key)
		}
	}
	l.lastGC = now
}
