package callee

import (
	"errors"
	"sync"
	"time"

	"code.justin.tv/sse/malachai/pkg/capabilities"
)

// ErrCapabilitiesCacheExpired is returned when the local capabilities cache
// is expired and the events client hasn't retrieved an update to refresh the
// cache.
var ErrCapabilitiesCacheExpired = errors.New("local capabilities cache has expired")

func newCalleeCapabilitiesCache(cacheExpiry time.Duration) *calleeCapabilitiesCache {
	return &calleeCapabilitiesCache{
		cache:       map[string]*capabilities.Capabilities{},
		cacheExpiry: cacheExpiry,
	}
}

type calleeCapabilitiesCache struct {
	cache         map[string]*capabilities.Capabilities
	lastRetrieved time.Time
	cacheExpiry   time.Duration
	lock          sync.RWMutex
}

func (ccc *calleeCapabilitiesCache) Update(updated map[string]*capabilities.Capabilities) {
	ccc.lock.Lock()
	ccc.cache = updated
	ccc.lastRetrieved = time.Now().UTC()
	ccc.lock.Unlock()
}

func (ccc *calleeCapabilitiesCache) Get(caller string) (*capabilities.Capabilities, error) {
	ccc.lock.RLock()
	if time.Now().UTC().Sub(ccc.lastRetrieved) > ccc.cacheExpiry {
		ccc.lock.RUnlock()
		return nil, ErrCapabilitiesCacheExpired
	}

	caps, ok := ccc.cache[caller]
	ccc.lock.RUnlock()

	if !ok {
		return nil, capabilities.ErrCapabilitiesNotFound
	}

	return caps, nil
}
