package auth

import (
	"sync"
	"time"
)

// Thresholds from spec 3: 5 attempts per email per 15 minutes, 20 per IP per
// hour. The email limit stops a targeted attack on one account; the IP limit
// stops a spray across many.
const (
	emailLimit  = 5
	emailWindow = 15 * time.Minute
	ipLimit     = 20
	ipWindow    = time.Hour
)

var (
	attemptMu sync.Mutex
	byEmail   = map[string][]time.Time{}
	byIP      = map[string][]time.Time{}
)

func prune(in []time.Time, cutoff time.Time) []time.Time {
	out := in[:0]
	for _, t := range in {
		if t.After(cutoff) {
			out = append(out, t)
		}
	}
	return out
}

func allowAttempt(email, ip string) bool {
	now := time.Now()

	attemptMu.Lock()
	defer attemptMu.Unlock()

	byEmail[email] = prune(byEmail[email], now.Add(-emailWindow))
	byIP[ip] = prune(byIP[ip], now.Add(-ipWindow))

	if len(byEmail[email]) >= emailLimit || len(byIP[ip]) >= ipLimit {
		return false
	}
	byEmail[email] = append(byEmail[email], now)
	byIP[ip] = append(byIP[ip], now)
	return true
}

func clearAttempts(email string) {
	attemptMu.Lock()
	delete(byEmail, email)
	attemptMu.Unlock()
}
