package cache

import (
	"sync"
	"time"
)

type Cache[K comparable, V any] struct {
	data map[K]entry[K, V]
	lock sync.RWMutex
}

type entry[K comparable, V any] struct {
	value      V
	expiration time.Time
}

func New[K comparable, V any]() *Cache[K, V] {
	return &Cache[K, V]{
		data: make(map[K]entry[K, V]),
	}
}

func (c *Cache[K, V]) Set(key K, value V, ttl time.Duration) {
	c.lock.Lock()
	defer c.lock.Unlock()

	c.data[key] = entry[K, V]{
		value:      value,
		expiration: time.Now().Add(ttl),
	}
}

func (c *Cache[K, V]) Get(key K) (V, bool) {
	c.lock.RLock()
	defer c.lock.RUnlock()

	entry, ok := c.data[key]
	if !ok || time.Now().After(entry.expiration) {
		delete(c.data, key)
		var zero V
		return zero, false
	}

	return entry.value, true
}

func (c *Cache[K, V]) Delete(key K) {
	c.lock.Lock()
	defer c.lock.Unlock()
	delete(c.data, key)
}