package auth

import (
	"context"
	"sync"
	"time"
)

// MemoryTokenStore implements TokenStore with in-memory storage
type MemoryTokenStore struct {
	blacklist map[string]time.Time
	mutex     sync.RWMutex
	// Optional cleaner to remove expired tokens
	cleanupInterval time.Duration
	stopCleanup     chan struct{}
}

// NewMemoryTokenStore creates a new in-memory token store
func NewMemoryTokenStore(cleanupInterval time.Duration) *MemoryTokenStore {
	store := &MemoryTokenStore{
		blacklist:       make(map[string]time.Time),
		mutex:           sync.RWMutex{},
		cleanupInterval: cleanupInterval,
		stopCleanup:     make(chan struct{}),
	}

	// Start background cleanup if interval > 0
	if cleanupInterval > 0 {
		go store.startCleanupRoutine()
	}

	return store
}

// IsBlacklisted checks if a token is in the blacklist
func (s *MemoryTokenStore) IsBlacklisted(ctx context.Context, token string) (bool, error) {
	s.mutex.RLock()
	defer s.mutex.RUnlock()

	expiry, exists := s.blacklist[token]
	if !exists {
		return false, nil
	}

	// If token has expired, we can remove it
	if time.Now().After(expiry) {
		// Don't remove here to avoid write lock during read operation
		return false, nil
	}

	return true, nil
}

// Blacklist adds a token to the blacklist
func (s *MemoryTokenStore) Blacklist(ctx context.Context, token string, expiry time.Time) error {
	s.mutex.Lock()
	defer s.mutex.Unlock()

	s.blacklist[token] = expiry
	return nil
}

// startCleanupRoutine periodically removes expired tokens
func (s *MemoryTokenStore) startCleanupRoutine() {
	ticker := time.NewTicker(s.cleanupInterval)
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			s.cleanup()
		case <-s.stopCleanup:
			return
		}
	}
}

// cleanup removes expired tokens from the blacklist
func (s *MemoryTokenStore) cleanup() {
	now := time.Now()
	s.mutex.Lock()
	defer s.mutex.Unlock()

	for token, expiry := range s.blacklist {
		if now.After(expiry) {
			delete(s.blacklist, token)
		}
	}
}

// Close stops the cleanup goroutine
func (s *MemoryTokenStore) Close() {
	if s.cleanupInterval > 0 {
		s.stopCleanup <- struct{}{}
	}
}
