package ratelimit

import (
	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"

	"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
)

// ProvideLoginRateLimiter creates a LoginRateLimiter for dependency injection
// CWE-307: Implements rate limiting and account lockout protection against brute force attacks
func ProvideLoginRateLimiter(redisClient redis.UniversalClient, cfg *config.Configuration, logger *zap.Logger) LoginRateLimiter {
	// Start with default config
	loginConfig := DefaultLoginRateLimiterConfig()

	// Override with configuration values if provided
	if cfg != nil {
		if cfg.LoginRateLimit.MaxAttemptsPerIP > 0 {
			loginConfig.MaxAttemptsPerIP = cfg.LoginRateLimit.MaxAttemptsPerIP
		}
		if cfg.LoginRateLimit.IPWindow > 0 {
			loginConfig.IPWindow = cfg.LoginRateLimit.IPWindow
		}
		if cfg.LoginRateLimit.MaxFailedAttemptsPerAccount > 0 {
			loginConfig.MaxFailedAttemptsPerAccount = cfg.LoginRateLimit.MaxFailedAttemptsPerAccount
		}
		if cfg.LoginRateLimit.AccountLockoutDuration > 0 {
			loginConfig.AccountLockoutDuration = cfg.LoginRateLimit.AccountLockoutDuration
		}
	}

	// Type assert to *redis.Client since LoginRateLimiter needs it
	client, ok := redisClient.(*redis.Client)
	if !ok {
		// If it's a cluster client or other type, log warning
		// This shouldn't happen in our standard setup
		logger.Warn("Redis client is not a standard client, login rate limiter may not work correctly")
		return NewLoginRateLimiter(nil, loginConfig, logger)
	}

	logger.Info("Login rate limiter initialized",
		zap.Int("max_attempts_per_ip", loginConfig.MaxAttemptsPerIP),
		zap.Duration("ip_window", loginConfig.IPWindow),
		zap.Int("max_failed_per_account", loginConfig.MaxFailedAttemptsPerAccount),
		zap.Duration("lockout_duration", loginConfig.AccountLockoutDuration))

	return NewLoginRateLimiter(client, loginConfig, logger)
}

// ProvideAuthFailureRateLimiter creates an AuthFailureRateLimiter for dependency injection
// CWE-307: Implements rate limiting for authorization failures to prevent privilege escalation attempts
// OWASP A01:2021: Broken Access Control - Rate limiting authorization failures
func ProvideAuthFailureRateLimiter(redisClient redis.UniversalClient, cfg *config.Configuration, logger *zap.Logger) AuthFailureRateLimiter {
	// Use default config with secure defaults for authorization failure protection
	authConfig := DefaultAuthFailureRateLimiterConfig()

	// Override defaults with configuration if provided
	// Allow configuration through environment variables for flexibility
	if cfg != nil {
		// These values could be configured via environment variables
		// For now, we use the secure defaults
		// TODO: Add auth failure rate limiting configuration to SecurityConfig
	}

	// Type assert to *redis.Client since AuthFailureRateLimiter needs it
	client, ok := redisClient.(*redis.Client)
	if !ok {
		// If it's a cluster client or other type, log warning
		logger.Warn("Redis client is not a standard client, auth failure rate limiter may not work correctly")
		return NewAuthFailureRateLimiter(nil, authConfig, logger)
	}

	logger.Info("Authorization failure rate limiter initialized",
		zap.Int("max_failures_per_user", authConfig.MaxFailuresPerUser),
		zap.Int("max_failures_per_resource", authConfig.MaxFailuresPerResource),
		zap.Duration("failure_window", authConfig.FailureWindow),
		zap.Duration("block_duration", authConfig.BlockDuration),
		zap.Int("alert_threshold", authConfig.AlertThreshold))

	return NewAuthFailureRateLimiter(client, authConfig, logger)
}
