<?php

declare(strict_types=1);

namespace App\Framework\SlidingWindow\Aggregator;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\SlidingWindow\WindowEntry;

/**
 * Advanced aggregator for rate limiting with burst detection and threat analysis
 *
 * @implements SlidingWindowAggregator<RateLimitResult>
 */
final readonly class RateLimitAggregator implements SlidingWindowAggregator
{
    public function __construct(
        private float $burstThreshold = 0.8,
        private float $minIntervalThreshold = 2.0
    ) {
    }

    public function aggregate(WindowEntry ...$entries): RateLimitResult
    {
        $timestamps = array_map(fn (WindowEntry $entry) => $entry->timestamp, $entries);
        $count = count($entries);

        if ($count < 2) {
            return new RateLimitResult(
                count: $count,
                timestamps: $timestamps
            );
        }

        // Sort timestamps for analysis
        $sortedTimestamps = $timestamps;
        usort($sortedTimestamps, fn (Timestamp $a, Timestamp $b) => $a->toFloat() <=> $b->toFloat());

        // Calculate intervals between requests
        $intervals = [];
        for ($i = 1; $i < count($sortedTimestamps); $i++) {
            $intervals[] = $sortedTimestamps[$i]->toFloat() - $sortedTimestamps[$i - 1]->toFloat();
        }

        // Burst analysis
        $avgInterval = array_sum($intervals) / count($intervals);
        $minInterval = min($intervals);

        // Calculate burst intensity (lower intervals = higher intensity)
        $burstIntensity = $avgInterval > 0 ? ($avgInterval - $minInterval) / $avgInterval : 1.0;
        $burstDetected = $burstIntensity > $this->burstThreshold && $minInterval < $this->minIntervalThreshold;

        // Threat analysis based on patterns
        $threatAnalysis = $this->analyzeThreatPatterns($intervals, $count, $burstIntensity);

        return new RateLimitResult(
            count: $count,
            timestamps: $timestamps,
            burstIntensity: $burstIntensity,
            minInterval: $minInterval,
            avgInterval: $avgInterval,
            burstDetected: $burstDetected,
            threatAnalysis: $threatAnalysis
        );
    }

    public function getIdentifier(): string
    {
        return 'rate_limit';
    }

    /**
     * Analyze threat patterns from request intervals
     */
    private function analyzeThreatPatterns(array $intervals, int $count, float $burstIntensity): array
    {
        $patterns = [];

        // High frequency attack
        if ($count > 100) {
            $patterns[] = 'high_frequency_attack';
        }

        // Burst attack pattern
        if ($burstIntensity > $this->burstThreshold) {
            $patterns[] = 'burst_attack';
        }

        // Sustained attack pattern (many requests with consistent timing)
        $intervalVariance = $this->calculateVariance($intervals);
        if ($intervalVariance < 0.1 && count($intervals) > 10) {
            $patterns[] = 'sustained_attack';
        }

        // Gradual ramp-up attack
        if ($this->detectRampUpPattern($intervals)) {
            $patterns[] = 'ramp_up_attack';
        }

        return [
            'patterns' => $patterns,
            'confidence' => $this->calculateConfidence($patterns, $count, $burstIntensity),
            'threat_score' => $this->calculateThreatScore($patterns, $count, $burstIntensity),
            'interval_variance' => $intervalVariance ?? 0.0,
        ];
    }

    /**
     * Calculate variance of intervals
     */
    private function calculateVariance(array $intervals): float
    {
        if (count($intervals) < 2) {
            return 0.0;
        }

        $mean = array_sum($intervals) / count($intervals);
        $variance = array_sum(array_map(fn ($x) => pow($x - $mean, 2), $intervals)) / count($intervals);

        return $variance;
    }

    /**
     * Detect ramp-up attack pattern (increasing frequency over time)
     */
    private function detectRampUpPattern(array $intervals): bool
    {
        if (count($intervals) < 5) {
            return false;
        }

        // Check if intervals are generally decreasing (frequency increasing)
        $decreasing = 0;
        for ($i = 1; $i < count($intervals); $i++) {
            if ($intervals[$i] < $intervals[$i - 1]) {
                $decreasing++;
            }
        }

        // If more than 70% of intervals are decreasing, it's likely a ramp-up
        return ($decreasing / (count($intervals) - 1)) > 0.7;
    }

    /**
     * Calculate confidence score for threat detection
     */
    private function calculateConfidence(array $patterns, int $count, float $burstIntensity): float
    {
        $confidence = 0.0;

        // Base confidence on number of patterns detected
        $confidence += count($patterns) * 0.2;

        // High request count increases confidence
        if ($count > 50) {
            $confidence += 0.3;
        }

        // High burst intensity increases confidence
        if ($burstIntensity > 0.8) {
            $confidence += 0.4;
        }

        return min(1.0, $confidence);
    }

    /**
     * Calculate threat score (0-100)
     */
    private function calculateThreatScore(array $patterns, int $count, float $burstIntensity): float
    {
        $score = 0.0;

        // Pattern-based scoring
        $patternScores = [
            'high_frequency_attack' => 30,
            'burst_attack' => 25,
            'sustained_attack' => 20,
            'ramp_up_attack' => 15,
        ];

        foreach ($patterns as $pattern) {
            $score += $patternScores[$pattern] ?? 0;
        }

        // Count-based scoring
        if ($count > 100) {
            $score += 20;
        } elseif ($count > 50) {
            $score += 10;
        }

        // Burst intensity scoring
        $score += $burstIntensity * 25;

        return min(100.0, $score);
    }
}
