package cache

import (
	"sync"
	"time"

	"github.com/fiskerinc/cloud-services/pkg/common"
	"github.com/pkg/errors"

	"github.com/fiskerinc/cloud-services/pkg/db/queries"
	"github.com/ReneKroon/ttlcache/v2"
)

const ApiKeyHeader = "Api-Key"

var (
	ErrInvalidToken = errors.New("invalid API token")
	ErrTokenExpired = errors.New("token is expired")
)

type APITokenCache struct {
	APITokens queries.APITokensInterface
	cache     *ttlcache.Cache
	onceCache sync.Once
}

func (a *APITokenCache) Get(key string) (string, error) {
	value, err := a.Cache().Get(key)
	if err == nil {
		apiToken, ok := value.(*common.APIToken)
		if !ok {
			return "", ErrInvalidToken
		}

		if apiToken.ExpiresAt != nil && apiToken.ExpiresAt.Before(time.Now()) {
			return "", ErrTokenExpired
		}

		return apiToken.Roles, nil
	} else if !errors.Is(err, ttlcache.ErrNotFound) {
		return "", err
	}

	item, err := a.APITokens.Get(key)
	if err != nil {
		return "", err
	}
	if item.ExpiresAt != nil && item.ExpiresAt.Before(time.Now()) {
		return "", ErrTokenExpired
	}

	err = a.Cache().Set(key, item)
	if err != nil {
		return "", err
	}

	return item.Roles, nil
}

func (a *APITokenCache) Cache() *ttlcache.Cache {
	a.onceCache.Do(func() {
		if a.cache == nil {
			cache := ttlcache.NewCache()
			cache.SetTTL(10 * time.Minute)
			cache.SetCacheSizeLimit(10)
			a.cache = cache
		}
	})

	return a.cache
}

func (a *APITokenCache) Close() {
	a.cache.Close()
	a.cache = nil
	a.APITokens = nil
}
