// Filename: internal/service/token_manager.go

package service

import (
	"fmt"
	"gemini-balancer/internal/models"
	"gemini-balancer/internal/repository"
	"gemini-balancer/internal/store"
	"gemini-balancer/internal/syncer"

	"github.com/sirupsen/logrus"
)

const TopicTokenChanged = "events:token_changed"

type TokenManager struct {
	repo   repository.AuthTokenRepository
	syncer *syncer.CacheSyncer[[]*models.AuthToken]
	logger *logrus.Entry
}

// NewTokenManager's signature is updated to accept the new repository.
func NewTokenManager(repo repository.AuthTokenRepository, store store.Store, logger *logrus.Logger) (*TokenManager, error) {
	tm := &TokenManager{
		repo:   repo,
		logger: logger.WithField("component", "TokenManager🔐"),
	}

	tokenLoader := func() ([]*models.AuthToken, error) {
		tm.logger.Info("Loading all auth tokens via repository...")
		tokens, err := tm.repo.GetAllTokensWithGroups()
		if err != nil {
			return nil, fmt.Errorf("failed to load auth tokens from repo: %w", err)
		}
		tm.logger.Infof("Successfully loaded and decrypted %d auth tokens into cache.", len(tokens))
		return tokens, nil
	}

	s, err := syncer.NewCacheSyncer(tokenLoader, store, TopicTokenChanged, logger)
	if err != nil {
		return nil, fmt.Errorf("failed to create token manager syncer: %w", err)
	}
	tm.syncer = s

	return tm, nil
}

func (tm *TokenManager) GetAllTokens() []*models.AuthToken {
	return tm.syncer.Get()
}

// BatchUpdateTokens is now a thin wrapper around the repository method.
func (tm *TokenManager) BatchUpdateTokens(incomingTokens []*models.TokenUpdateRequest) error {
	tm.logger.Info("Delegating BatchUpdateTokens to repository...")

	if err := tm.repo.BatchUpdateTokens(incomingTokens); err != nil {
		tm.logger.Errorf("Repository failed to batch update tokens: %v", err)
		return err
	}

	tm.logger.Info("BatchUpdateTokens finished successfully. Invalidating cache.")
	return tm.Invalidate()
}

func (tm *TokenManager) Invalidate() error {
	return tm.syncer.Invalidate()
}

func (tm *TokenManager) Stop() {
	tm.syncer.Stop()
}
