<?php

declare(strict_types=1);

namespace App\Framework\Waf\MachineLearning;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\Waf\MachineLearning\ValueObjects\AnomalyDetection;
use App\Framework\Waf\MachineLearning\ValueObjects\BehaviorFeature;

/**
 * Result of machine learning analysis
 */
final readonly class MachineLearningResult
{
    /**
     * @param BehaviorFeature[] $features
     * @param AnomalyDetection[] $anomalies
     */
    public function __construct(
        public array $features,
        public array $anomalies,
        public Percentage $confidence,
        public Duration $processingTime,
        public bool $enabled,
        public array $extractorResults = [],
        public array $detectorResults = [],
        public array $baselineStats = [],
        public ?string $error = null
    ) {
    }

    /**
     * Check if any anomalies were detected
     */
    public function hasAnomalies(): bool
    {
        return ! empty($this->anomalies);
    }

    /**
     * Get the highest anomaly score
     */
    public function getMaxAnomalyScore(): float
    {
        if (empty($this->anomalies)) {
            return 0.0;
        }

        return max(array_map(fn (AnomalyDetection $a) => $a->anomalyScore, $this->anomalies));
    }

    /**
     * Get anomalies by type
     */
    public function getAnomaliesByType(AnomalyType $type): array
    {
        return array_filter(
            $this->anomalies,
            fn (AnomalyDetection $a) => $a->type === $type
        );
    }

    /**
     * Get features by behavior type
     */
    public function getFeaturesByBehaviorType(BehaviorType $type): array
    {
        return array_filter(
            $this->features,
            fn (BehaviorFeature $f) => $f->type === $type
        );
    }

    /**
     * Get critical anomalies (high confidence and score)
     */
    public function getCriticalAnomalies(): array
    {
        return array_filter(
            $this->anomalies,
            fn (AnomalyDetection $a) => $a->confidence->getValue() >= 90.0 && $a->anomalyScore >= 0.8
        );
    }

    /**
     * Get processing summary
     */
    public function getSummary(): array
    {
        return [
            'enabled' => $this->enabled,
            'feature_count' => count($this->features),
            'anomaly_count' => count($this->anomalies),
            'critical_anomaly_count' => count($this->getCriticalAnomalies()),
            'max_anomaly_score' => $this->getMaxAnomalyScore(),
            'confidence' => $this->confidence->getValue(),
            'processing_time_ms' => $this->processingTime->toMilliseconds(),
            'has_error' => $this->error !== null,
            'error_message' => $this->error,
        ];
    }

    /**
     * Get detailed analysis report
     */
    public function getDetailedReport(): array
    {
        $report = $this->getSummary();

        // Add extractor details
        $report['extractors'] = $this->extractorResults;

        // Add detector details
        $report['detectors'] = $this->detectorResults;

        // Add baseline statistics
        $report['baselines'] = $this->baselineStats;

        // Add anomaly details
        $report['anomaly_details'] = array_map(
            fn (AnomalyDetection $a) => [
                'type' => $a->type->value,
                'behavior_type' => $a->behaviorType->value,
                'score' => $a->anomalyScore,
                'confidence' => $a->confidence->getValue(),
                'description' => $a->description,
                'feature_count' => count($a->features),
                'evidence_keys' => array_keys($a->evidence),
            ],
            $this->anomalies
        );

        // Add feature summary by type
        $featuresByType = [];
        foreach ($this->features as $feature) {
            $typeKey = $feature->type->value;
            if (! isset($featuresByType[$typeKey])) {
                $featuresByType[$typeKey] = [];
            }
            $featuresByType[$typeKey][] = [
                'name' => $feature->name,
                'value' => $feature->value,
                'unit' => $feature->unit,
                'normalized' => $feature->normalizedValue,
                'z_score' => $feature->zScore,
            ];
        }
        $report['features_by_type'] = $featuresByType;

        return $report;
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'enabled' => $this->enabled,
            'confidence' => $this->confidence->getValue(),
            'processing_time_ms' => $this->processingTime->toMilliseconds(),
            'feature_count' => count($this->features),
            'anomaly_count' => count($this->anomalies),
            'max_anomaly_score' => $this->getMaxAnomalyScore(),
            'has_anomalies' => $this->hasAnomalies(),
            'critical_anomaly_count' => count($this->getCriticalAnomalies()),
            'error' => $this->error,
            'summary' => $this->getSummary(),
        ];
    }

    /**
     * Check if analysis was successful
     */
    public function isSuccessful(): bool
    {
        return $this->enabled && $this->error === null;
    }

    /**
     * Check if immediate action is required
     */
    public function requiresImmediateAction(): bool
    {
        return $this->getMaxAnomalyScore() >= 0.9 || count($this->getCriticalAnomalies()) > 0;
    }
}
