package connectsrv

import (
	"sync"
	"time"
)

// activeUsers tracks distinct authenticated accounts by last-action time, backing
// the in-memory active_users gauge. It is single-process by design (the gateway is
// single-instance in the MVP, docs/ARCHITECTURE.md §10): the distinct count is
// correct for one process, resets on restart, and is a live operational gauge, not
// a billing figure. Memory is bounded by the number of distinct accounts active
// within the longest window; stale entries are pruned on observation.
type activeUsers struct {
	mu       sync.Mutex
	lastSeen map[string]time.Time
	now      func() time.Time
}

// newActiveUsers returns an empty tracker using the wall clock.
func newActiveUsers() *activeUsers {
	return &activeUsers{lastSeen: make(map[string]time.Time), now: time.Now}
}

// seen records that account uid performed an authenticated action now.
func (a *activeUsers) seen(uid string) {
	if uid == "" {
		return
	}
	a.mu.Lock()
	a.lastSeen[uid] = a.now()
	a.mu.Unlock()
}

// counts returns, for each window, the number of distinct accounts last seen
// within it, pruning entries older than the longest window in the same pass.
func (a *activeUsers) counts(windows []time.Duration) []int {
	a.mu.Lock()
	defer a.mu.Unlock()

	now := a.now()
	var longest time.Duration
	for _, w := range windows {
		if w > longest {
			longest = w
		}
	}

	res := make([]int, len(windows))
	for uid, ts := range a.lastSeen {
		age := now.Sub(ts)
		if age > longest {
			delete(a.lastSeen, uid)
			continue
		}
		for i, w := range windows {
			if age <= w {
				res[i]++
			}
		}
	}
	return res
}
