package service

import (
	"crypto/md5"
	"fmt"
	"sync"
	"time"
)

// rateLimits defines minimum seconds between the same action by the same user on the same work.
var rateLimits = map[string]int64{
	"view":     60,
	"download": 300,
	"like":     3600,
}

// RateLimiter provides per-user, per-action, per-work rate limiting backed by an in-memory store.
// The store is never persisted; it resets on service restart (same behaviour as the Python version).
type RateLimiter struct {
	mu sync.Mutex
	// fingerprint → actionType → workID → last unix timestamp
	actions map[string]map[string]map[string]int64
}

// NewRateLimiter allocates a new empty RateLimiter.
func NewRateLimiter() *RateLimiter {
	return &RateLimiter{
		actions: make(map[string]map[string]map[string]int64),
	}
}

// CanPerform returns true and records the timestamp if the rate limit window has elapsed.
// Returns false if the action is too frequent.
func (rl *RateLimiter) CanPerform(fingerprint, actionType, workID string) bool {
	rl.mu.Lock()
	defer rl.mu.Unlock()

	limit, ok := rateLimits[actionType]
	if !ok {
		return true
	}

	now := time.Now().Unix()

	if rl.actions[fingerprint] == nil {
		rl.actions[fingerprint] = make(map[string]map[string]int64)
	}
	if rl.actions[fingerprint][actionType] == nil {
		rl.actions[fingerprint][actionType] = make(map[string]int64)
	}

	last := rl.actions[fingerprint][actionType][workID]
	if now-last >= limit {
		rl.actions[fingerprint][actionType][workID] = now
		return true
	}
	return false
}

// Fingerprint creates an MD5 hex string from IP and User-Agent for rate-limit keying.
func Fingerprint(ip, userAgent string) string {
	h := md5.Sum([]byte(ip + ":" + userAgent))
	return fmt.Sprintf("%x", h)
}
