package crypto

import (
	"sync"
)

// UEKCache holds decrypted User Encryption Keys in memory, keyed by user ID.
// Keys are loaded on login and evicted on logout / token expiry.
//
// This is the trust boundary: UEKs exist in plaintext only in server memory,
// never on disk or in the database.
type UEKCache struct {
	mu    sync.RWMutex
	store map[string][]byte
}

// NewUEKCache creates a new empty cache.
func NewUEKCache() *UEKCache {
	return &UEKCache{store: make(map[string][]byte)}
}

// Store caches a UEK for the given user ID.
func (c *UEKCache) Store(userID string, uek []byte) {
	c.mu.Lock()
	defer c.mu.Unlock()
	// Copy to avoid caller mutation
	key := make([]byte, len(uek))
	copy(key, uek)
	c.store[userID] = key
}

// Load retrieves the UEK for a user. Returns (uek, true) if present.
func (c *UEKCache) Load(userID string) ([]byte, bool) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	uek, ok := c.store[userID]
	if !ok {
		return nil, false
	}
	// Return a copy
	out := make([]byte, len(uek))
	copy(out, uek)
	return out, true
}

// Evict removes the UEK for a user (logout / session expiry).
func (c *UEKCache) Evict(userID string) {
	c.mu.Lock()
	defer c.mu.Unlock()
	// Zero the memory before deleting
	if uek, ok := c.store[userID]; ok {
		for i := range uek {
			uek[i] = 0
		}
	}
	delete(c.store, userID)
}

// Size returns the number of cached UEKs (for diagnostics).
func (c *UEKCache) Size() int {
	c.mu.RLock()
	defer c.mu.RUnlock()
	return len(c.store)
}
