<?php

declare(strict_types=1);

namespace App\Framework\DDoS;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Score;

/**
 * DDoS Protection Configuration using Framework Value Objects
 */
final readonly class DDoSConfig
{
    public function __construct(
        public bool $enabled = true,
        public ?Score $volumetricThreshold = null, // Detection threshold for volume attacks
        public ?Score $distributedThreshold = null, // Detection threshold for distributed attacks
        public ?Score $applicationThreshold = null, // Detection threshold for application attacks
        public ?Score $protocolThreshold = null, // Detection threshold for protocol attacks
        public ?Score $botnetThreshold = null, // Detection threshold for botnet attacks
        public ?Score $slowAttackThreshold = null, // Detection threshold for slow attacks
        public ?Score $coordinatedThreshold = null, // Detection threshold for coordinated attacks
        public ?Score $amplificationThreshold = null, // Detection threshold for amplification attacks
        public ?Duration $analysisWindow = null, // 5 minutes default
        public ?Duration $maxProcessingTime = null, // max time for analysis
        public bool $enableGeographicBlocking = true,
        public bool $enableBotDetection = true,
        public bool $enableMachineLearning = false,
        public array $trustedIps = [],
        public array $exemptPaths = ['/health', '/ping'],
        public ?Score $criticalThreatThreshold = null,
        public ?Score $highThreatThreshold = null,
        public ?Score $mediumThreatThreshold = null,
        public bool $logAllAssessments = false,
        public bool $logOnlyThreats = true,
        public ?Duration $cacheAssessmentDuration = null,
        public array $blockedCountries = [],
        public array $allowedCountries = [],
        public bool $enableCaptchaChallenge = true,
        public bool $enableProofOfWork = false,
        public int $maxRequestsPerIpPerMinute = 60,
        public int $maxRequestsPerIpPerHour = 1000,
        public bool $enableAdaptiveRateLimiting = true,
        public bool $enableCircuitBreakerIntegration = true,
        public ?Duration $rateLimitWindow = null, // 1 minute default
        public ?Duration $circuitBreakerTimeout = null, // 30 seconds default
        public ?Duration $assessmentRetentionPeriod = null // 1 hour default
    ) {
    }

    /**
     * Get volumetric attack threshold with default fallback
     */
    public function getVolumetricThreshold(): Score
    {
        return $this->volumetricThreshold ?? Score::high(); // 0.7
    }

    /**
     * Get distributed attack threshold with default fallback
     */
    public function getDistributedThreshold(): Score
    {
        return $this->distributedThreshold ?? Score::medium(); // 0.5
    }

    /**
     * Get application layer attack threshold with default fallback
     */
    public function getApplicationThreshold(): Score
    {
        return $this->applicationThreshold ?? Score::high(); // 0.7
    }

    /**
     * Get protocol attack threshold with default fallback
     */
    public function getProtocolThreshold(): Score
    {
        return $this->protocolThreshold ?? Score::high(); // 0.7
    }

    /**
     * Get botnet attack threshold with default fallback
     */
    public function getBotnetThreshold(): Score
    {
        return $this->botnetThreshold ?? Score::medium(); // 0.5
    }

    /**
     * Get slow attack threshold with default fallback
     */
    public function getSlowAttackThreshold(): Score
    {
        return $this->slowAttackThreshold ?? Score::low(); // 0.2
    }

    /**
     * Get coordinated attack threshold with default fallback
     */
    public function getCoordinatedThreshold(): Score
    {
        return $this->coordinatedThreshold ?? Score::medium(); // 0.5
    }

    /**
     * Get amplification attack threshold with default fallback
     */
    public function getAmplificationThreshold(): Score
    {
        return $this->amplificationThreshold ?? Score::high(); // 0.7
    }

    /**
     * Get critical threat threshold with default fallback
     */
    public function getCriticalThreatThreshold(): Score
    {
        return $this->criticalThreatThreshold ?? Score::critical(); // 0.9
    }

    /**
     * Get high threat threshold with default fallback
     */
    public function getHighThreatThreshold(): Score
    {
        return $this->highThreatThreshold ?? Score::high(); // 0.7
    }

    /**
     * Get medium threat threshold with default fallback
     */
    public function getMediumThreatThreshold(): Score
    {
        return $this->mediumThreatThreshold ?? Score::medium(); // 0.5
    }

    /**
     * Get analysis window with default fallback
     */
    public function getAnalysisWindow(): Duration
    {
        return $this->analysisWindow ?? Duration::fromMinutes(5);
    }

    /**
     * Get max processing time with default fallback
     */
    public function getMaxProcessingTime(): Duration
    {
        return $this->maxProcessingTime ?? Duration::fromMilliseconds(100);
    }

    /**
     * Get cache assessment duration with default fallback
     */
    public function getCacheAssessmentDuration(): Duration
    {
        return $this->cacheAssessmentDuration ?? Duration::fromMinutes(5);
    }

    /**
     * Get rate limit window with default fallback
     */
    public function getRateLimitWindow(): Duration
    {
        return $this->rateLimitWindow ?? Duration::oneMinute();
    }

    /**
     * Get circuit breaker timeout with default fallback
     */
    public function getCircuitBreakerTimeout(): Duration
    {
        return $this->circuitBreakerTimeout ?? Duration::fromSeconds(30);
    }

    /**
     * Get assessment retention period with default fallback
     */
    public function getAssessmentRetentionPeriod(): Duration
    {
        return $this->assessmentRetentionPeriod ?? Duration::oneHour();
    }

    /**
     * Create development configuration (more permissive)
     */
    public static function development(): self
    {
        return new self(
            enabled: true,
            volumetricThreshold: new Score(0.8), // Higher threshold for dev
            distributedThreshold: new Score(0.9), // Very high threshold for dev
            applicationThreshold: new Score(0.8),
            protocolThreshold: new Score(0.8),
            botnetThreshold: new Score(0.7),
            slowAttackThreshold: new Score(0.4),
            coordinatedThreshold: new Score(0.7),
            amplificationThreshold: new Score(0.8),
            analysisWindow: Duration::fromMinutes(10), // Longer window for dev
            maxProcessingTime: Duration::fromMilliseconds(500), // More time for analysis
            enableGeographicBlocking: false,
            enableBotDetection: false,
            enableMachineLearning: false,
            criticalThreatThreshold: Score::critical(),
            highThreatThreshold: Score::high(),
            mediumThreatThreshold: Score::medium(),
            logAllAssessments: true,
            trustedIps: ['127.0.0.1', '::1'],
            maxRequestsPerIpPerMinute: 300,
            maxRequestsPerIpPerHour: 5000,
            cacheAssessmentDuration: Duration::fromMinutes(1), // Shorter cache for dev
            rateLimitWindow: Duration::fromMinutes(2),
            assessmentRetentionPeriod: Duration::fromMinutes(30)
        );
    }

    /**
     * Create production configuration (strict security)
     */
    public static function production(): self
    {
        return new self(
            enabled: true,
            volumetricThreshold: new Score(0.6), // Strict threshold for production
            distributedThreshold: new Score(0.5), // Medium threshold for distribution
            applicationThreshold: new Score(0.6),
            protocolThreshold: new Score(0.6),
            botnetThreshold: new Score(0.4), // Lower threshold for bots
            slowAttackThreshold: new Score(0.2),
            coordinatedThreshold: new Score(0.4),
            amplificationThreshold: new Score(0.6),
            analysisWindow: Duration::fromMinutes(5),
            maxProcessingTime: Duration::fromMilliseconds(50), // Strict timing
            enableGeographicBlocking: true,
            enableBotDetection: true,
            enableMachineLearning: true,
            criticalThreatThreshold: Score::critical(),
            highThreatThreshold: Score::high(),
            mediumThreatThreshold: Score::medium(),
            logOnlyThreats: true,
            maxRequestsPerIpPerMinute: 30,
            maxRequestsPerIpPerHour: 500,
            enableAdaptiveRateLimiting: true,
            enableCircuitBreakerIntegration: true,
            cacheAssessmentDuration: Duration::fromMinutes(10), // Longer cache for efficiency
            rateLimitWindow: Duration::oneMinute(),
            circuitBreakerTimeout: Duration::fromSeconds(15), // Faster recovery
            assessmentRetentionPeriod: Duration::fromHours(4) // Keep for analysis
        );
    }

    /**
     * Create testing configuration (disabled protection)
     */
    public static function testing(): self
    {
        return new self(
            enabled: false,
            volumetricThreshold: Score::max(), // Very high threshold for testing
            distributedThreshold: Score::max(),
            applicationThreshold: Score::max(),
            protocolThreshold: Score::max(),
            botnetThreshold: Score::max(),
            slowAttackThreshold: Score::max(),
            coordinatedThreshold: Score::max(),
            amplificationThreshold: Score::max(),
            analysisWindow: Duration::fromSeconds(10),
            maxProcessingTime: Duration::fromMilliseconds(1000),
            criticalThreatThreshold: Score::critical(),
            highThreatThreshold: Score::high(),
            mediumThreatThreshold: Score::medium(),
            logAllAssessments: false,
            logOnlyThreats: false,
            cacheAssessmentDuration: Duration::fromSeconds(1),
            assessmentRetentionPeriod: Duration::fromMinutes(1)
        );
    }

    /**
     * Check if IP is trusted
     */
    public function isTrustedIp(string $ip): bool
    {
        return in_array($ip, $this->trustedIps, true);
    }

    /**
     * Check if path is exempt from protection
     */
    public function isExemptPath(string $path): bool
    {
        foreach ($this->exemptPaths as $exemptPath) {
            if (str_starts_with($path, $exemptPath)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if country is blocked
     */
    public function isCountryBlocked(string $countryCode): bool
    {
        if (! empty($this->allowedCountries)) {
            return ! in_array($countryCode, $this->allowedCountries, true);
        }

        return in_array($countryCode, $this->blockedCountries, true);
    }

    /**
     * Get threat threshold for level
     */
    public function getThreatThreshold(string $level): Score
    {
        return match ($level) {
            'critical' => $this->getCriticalThreatThreshold(),
            'high' => $this->getHighThreatThreshold(),
            'medium' => $this->getMediumThreatThreshold(),
            default => Score::zero()
        };
    }

    /**
     * Check if assessment should be logged
     */
    public function shouldLogAssessment(Score $confidence): bool
    {
        if ($this->logAllAssessments) {
            return true;
        }

        if ($this->logOnlyThreats) {
            return $confidence->isAbove($this->getMediumThreatThreshold());
        }

        return false;
    }

    /**
     * Get rate limit for IP based on configuration
     */
    public function getRateLimitForIp(string $ip): array
    {
        if ($this->isTrustedIp($ip)) {
            return [
                'requests_per_minute' => $this->maxRequestsPerIpPerMinute * 10,
                'requests_per_hour' => $this->maxRequestsPerIpPerHour * 10,
                'window' => $this->rateLimitWindow,
            ];
        }

        return [
            'requests_per_minute' => $this->maxRequestsPerIpPerMinute,
            'requests_per_hour' => $this->maxRequestsPerIpPerHour,
            'window' => $this->getRateLimitWindow(),
        ];
    }

    /**
     * Get cache TTL in seconds for external systems
     */
    public function getCacheTtlSeconds(): int
    {
        return $this->getCacheAssessmentDuration()->toCacheSeconds();
    }

    /**
     * Get analysis window in seconds for legacy systems
     */
    public function getAnalysisWindowSeconds(): int
    {
        return (int) $this->getAnalysisWindow()->toSeconds();
    }

    /**
     * Check if processing time exceeded threshold
     */
    public function isProcessingTimeExceeded(Duration $actualTime): bool
    {
        return $actualTime->greaterThan($this->getMaxProcessingTime());
    }

    /**
     * Get timeout configuration for CircuitBreaker
     */
    public function getCircuitBreakerConfig(): array
    {
        return [
            'timeout' => $this->getCircuitBreakerTimeout(),
            'enabled' => $this->enableCircuitBreakerIntegration,
            'failure_threshold' => 5, // Allow 5 failures before opening
            'recovery_timeout' => Duration::fromMinutes(1),
        ];
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'enabled' => $this->enabled,
            'volumetric_threshold' => $this->getVolumetricThreshold()->value(),
            'distributed_threshold' => $this->getDistributedThreshold()->value(),
            'analysis_window' => $this->getAnalysisWindow()->toHumanReadable(),
            'max_processing_time' => $this->getMaxProcessingTime()->toHumanReadable(),
            'enable_geographic_blocking' => $this->enableGeographicBlocking,
            'enable_bot_detection' => $this->enableBotDetection,
            'enable_machine_learning' => $this->enableMachineLearning,
            'trusted_ips_count' => count($this->trustedIps),
            'exempt_paths_count' => count($this->exemptPaths),
            'attack_thresholds' => [
                'volumetric' => $this->getVolumetricThreshold()->value(),
                'distributed' => $this->getDistributedThreshold()->value(),
                'application' => $this->getApplicationThreshold()->value(),
                'protocol' => $this->getProtocolThreshold()->value(),
                'botnet' => $this->getBotnetThreshold()->value(),
                'slow_attack' => $this->getSlowAttackThreshold()->value(),
                'coordinated' => $this->getCoordinatedThreshold()->value(),
                'amplification' => $this->getAmplificationThreshold()->value(),
            ],
            'threat_thresholds' => [
                'critical' => $this->getCriticalThreatThreshold()->value(),
                'high' => $this->getHighThreatThreshold()->value(),
                'medium' => $this->getMediumThreatThreshold()->value(),
            ],
            'rate_limits' => [
                'requests_per_minute' => $this->maxRequestsPerIpPerMinute,
                'requests_per_hour' => $this->maxRequestsPerIpPerHour,
                'window' => $this->getRateLimitWindow()->toHumanReadable(),
            ],
            'integrations' => [
                'adaptive_rate_limiting' => $this->enableAdaptiveRateLimiting,
                'circuit_breaker' => $this->enableCircuitBreakerIntegration,
                'captcha_challenge' => $this->enableCaptchaChallenge,
                'proof_of_work' => $this->enableProofOfWork,
            ],
            'durations' => [
                'cache_assessment' => $this->getCacheAssessmentDuration()->toHumanReadable(),
                'circuit_breaker_timeout' => $this->getCircuitBreakerTimeout()->toHumanReadable(),
                'retention_period' => $this->getAssessmentRetentionPeriod()->toHumanReadable(),
            ],
        ];
    }

    /**
     * Create adaptive configuration based on current system load
     */
    public static function adaptive(float $systemLoad = 0.5): self
    {
        // More restrictive when system under load
        $baseConfig = $systemLoad > 0.8 ? self::production() : self::development();

        // Make thresholds more sensitive under high system load
        $loadMultiplier = max(0.1, 1.0 - $systemLoad * 0.5);
        $adaptiveProcessingTime = $baseConfig->getMaxProcessingTime()->multiply(1.0 - $systemLoad * 0.3);

        return new self(
            enabled: $baseConfig->enabled,
            volumetricThreshold: new Score(max(0.1, $baseConfig->getVolumetricThreshold()->value() * $loadMultiplier)),
            distributedThreshold: new Score(max(0.1, $baseConfig->getDistributedThreshold()->value() * $loadMultiplier)),
            applicationThreshold: new Score(max(0.1, $baseConfig->getApplicationThreshold()->value() * $loadMultiplier)),
            protocolThreshold: new Score(max(0.1, $baseConfig->getProtocolThreshold()->value() * $loadMultiplier)),
            botnetThreshold: new Score(max(0.1, $baseConfig->getBotnetThreshold()->value() * $loadMultiplier)),
            slowAttackThreshold: new Score(max(0.1, $baseConfig->getSlowAttackThreshold()->value() * $loadMultiplier)),
            coordinatedThreshold: new Score(max(0.1, $baseConfig->getCoordinatedThreshold()->value() * $loadMultiplier)),
            amplificationThreshold: new Score(max(0.1, $baseConfig->getAmplificationThreshold()->value() * $loadMultiplier)),
            analysisWindow: $baseConfig->getAnalysisWindow(),
            maxProcessingTime: $adaptiveProcessingTime,
            enableGeographicBlocking: $baseConfig->enableGeographicBlocking,
            enableBotDetection: $baseConfig->enableBotDetection,
            enableMachineLearning: $systemLoad < 0.6, // Disable ML under high load
            criticalThreatThreshold: $baseConfig->getCriticalThreatThreshold(),
            highThreatThreshold: $baseConfig->getHighThreatThreshold(),
            mediumThreatThreshold: $baseConfig->getMediumThreatThreshold(),
            trustedIps: $baseConfig->trustedIps,
            exemptPaths: $baseConfig->exemptPaths,
            logAllAssessments: $baseConfig->logAllAssessments,
            logOnlyThreats: $baseConfig->logOnlyThreats,
            cacheAssessmentDuration: $baseConfig->getCacheAssessmentDuration(),
            blockedCountries: $baseConfig->blockedCountries,
            allowedCountries: $baseConfig->allowedCountries,
            enableCaptchaChallenge: $baseConfig->enableCaptchaChallenge,
            enableProofOfWork: $baseConfig->enableProofOfWork,
            maxRequestsPerIpPerMinute: (int) ($baseConfig->maxRequestsPerIpPerMinute * (1.0 - $systemLoad * 0.4)),
            maxRequestsPerIpPerHour: (int) ($baseConfig->maxRequestsPerIpPerHour * (1.0 - $systemLoad * 0.4)),
            enableAdaptiveRateLimiting: true, // Always enable adaptive under load
            enableCircuitBreakerIntegration: true
        );
    }
}
