// Filename: internal/service/security_service.go

package service

import (
	"context"
	"crypto/sha256" // [NEW] Import crypto library for hashing
	"encoding/hex"  // [NEW] Import hex encoding
	"fmt"
	"gemini-balancer/internal/models"
	"gemini-balancer/internal/repository" // [NEW] Import repository
	"gemini-balancer/internal/settings"
	"gemini-balancer/internal/store"

	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
)

const loginAttemptsKey = "security:login_attempts"

type SecurityService struct {
	repo            repository.AuthTokenRepository
	store           store.Store
	SettingsManager *settings.SettingsManager
	logger          *logrus.Entry
}

// NewSecurityService signature updated to accept the repository.
func NewSecurityService(repo repository.AuthTokenRepository, store store.Store, settingsManager *settings.SettingsManager, logger *logrus.Logger) *SecurityService {
	return &SecurityService{
		repo:            repo,
		store:           store,
		SettingsManager: settingsManager,
		logger:          logger.WithField("component", "SecurityService🛡️"),
	}
}

// AuthenticateToken is now secure and efficient.
func (s *SecurityService) AuthenticateToken(tokenValue string) (*models.AuthToken, error) {
	if tokenValue == "" {
		return nil, gorm.ErrRecordNotFound
	}
	// [REFACTORED]
	// 1. Hash the incoming plaintext token.
	hash := sha256.Sum256([]byte(tokenValue))
	tokenHash := hex.EncodeToString(hash[:])

	// 2. Delegate the lookup to the repository using the hash.
	return s.repo.GetTokenByHashedValue(tokenHash)
}

// IsIPBanned
func (s *SecurityService) IsIPBanned(ctx context.Context, ip string) (bool, error) {
	banKey := fmt.Sprintf("banned_ip:%s", ip)
	return s.store.Exists(ctx, banKey)
}

// RecordFailedLoginAttempt
func (s *SecurityService) RecordFailedLoginAttempt(ctx context.Context, ip string) error {
	if !s.SettingsManager.IsIPBanEnabled() {
		return nil
	}

	count, err := s.store.HIncrBy(ctx, loginAttemptsKey, ip, 1)
	if err != nil {
		return err
	}

	maxAttempts := s.SettingsManager.GetMaxLoginAttempts()
	if count >= int64(maxAttempts) {
		banDuration := s.SettingsManager.GetIPBanDuration()
		banKey := fmt.Sprintf("banned_ip:%s", ip)

		if err := s.store.Set(ctx, banKey, []byte("1"), banDuration); err != nil {
			return err
		}
		s.logger.Warnf("IP BANNED: IP [%s] has been banned for %v due to excessive failed login attempts.", ip, banDuration)

		s.store.HDel(ctx, loginAttemptsKey, ip)
	}

	return nil
}
