<?php

declare(strict_types=1);

namespace App\Framework\Waf\MachineLearning\ValueObjects;

use App\Framework\Core\ValueObjects\Score;

/**
 * Result of behavioral anomaly detection analysis
 *
 * Immutable value object representing the outcome of ML-based behavioral analysis
 */
final readonly class BehaviorAnomalyResult
{
    /**
     * @param Score $anomalyScore Overall anomaly confidence (0.0-1.0)
     * @param bool $isAnomalous Whether behavior is classified as anomalous
     * @param array<string, Score> $featureScores Individual feature anomaly scores
     * @param array<string, mixed> $detectedPatterns Specific attack patterns detected
     * @param string $primaryIndicator Main indicator of anomaly
     * @param array<string, mixed> $metadata Additional analysis metadata
     */
    public function __construct(
        public Score $anomalyScore,
        public bool $isAnomalous,
        public array $featureScores,
        public array $detectedPatterns,
        public string $primaryIndicator,
        public array $metadata = []
    ) {}

    /**
     * Create result indicating normal behavior
     */
    public static function normal(string $reason = 'No anomalous patterns detected'): self
    {
        return new self(
            anomalyScore: Score::zero(),
            isAnomalous: false,
            featureScores: [],
            detectedPatterns: [],
            primaryIndicator: $reason,
            metadata: ['analysis_type' => 'normal']
        );
    }

    /**
     * Create result indicating low-confidence anomaly
     */
    public static function lowConfidence(Score $score, array $featureScores = []): self
    {
        return new self(
            anomalyScore: $score,
            isAnomalous: false,
            featureScores: $featureScores,
            detectedPatterns: [],
            primaryIndicator: 'Low confidence anomaly - monitoring recommended',
            metadata: ['analysis_type' => 'low_confidence']
        );
    }

    /**
     * Create result indicating confirmed anomaly
     */
    public static function anomalous(
        Score $score,
        array $featureScores,
        array $detectedPatterns,
        string $primaryIndicator
    ): self {
        return new self(
            anomalyScore: $score,
            isAnomalous: true,
            featureScores: $featureScores,
            detectedPatterns: $detectedPatterns,
            primaryIndicator: $primaryIndicator,
            metadata: ['analysis_type' => 'confirmed_anomaly']
        );
    }

    /**
     * Get anomaly severity based on score level
     */
    public function getSeverity(): string
    {
        return $this->anomalyScore->toLevel()->value;
    }

    /**
     * Check if anomaly requires immediate action
     */
    public function requiresImmediateAction(): bool
    {
        return $this->isAnomalous && $this->anomalyScore->isCritical();
    }

    /**
     * Get recommended action based on score level
     */
    public function getRecommendedAction(): string
    {
        if (!$this->isAnomalous) {
            return 'monitor';
        }

        return $this->anomalyScore->toLevel()->getRecommendedAction();
    }

    /**
     * Get top contributing features (sorted by score)
     */
    public function getTopContributors(int $limit = 3): array
    {
        if (empty($this->featureScores)) {
            return [];
        }

        $sorted = $this->featureScores;
        uasort($sorted, fn(Score $a, Score $b) => $b->value() <=> $a->value());

        return array_slice($sorted, 0, $limit, true);
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'anomaly_score' => $this->anomalyScore->toArray(),
            'is_anomalous' => $this->isAnomalous,
            'severity' => $this->getSeverity(),
            'feature_scores' => array_map(
                fn(Score $score) => $score->toArray(),
                $this->featureScores
            ),
            'detected_patterns' => $this->detectedPatterns,
            'primary_indicator' => $this->primaryIndicator,
            'recommended_action' => $this->getRecommendedAction(),
            'top_contributors' => array_map(
                fn(Score $score) => $score->value(),
                $this->getTopContributors()
            ),
            'metadata' => $this->metadata
        ];
    }

    /**
     * Merge with another anomaly result using weighted combination
     */
    public function merge(self $other, float $weight = 0.5): self
    {
        $combinedScore = $this->anomalyScore->combine($other->anomalyScore, $weight);

        return new self(
            anomalyScore: $combinedScore,
            isAnomalous: $this->isAnomalous || $other->isAnomalous,
            featureScores: array_merge($this->featureScores, $other->featureScores),
            detectedPatterns: array_merge($this->detectedPatterns, $other->detectedPatterns),
            primaryIndicator: $combinedScore->isAbove($this->anomalyScore)
                ? $other->primaryIndicator
                : $this->primaryIndicator,
            metadata: array_merge($this->metadata, $other->metadata, [
                'merged' => true,
                'merge_weight' => $weight
            ])
        );
    }

    /**
     * String representation
     */
    public function toString(): string
    {
        $status = $this->isAnomalous ? 'ANOMALOUS' : 'NORMAL';
        $score = $this->anomalyScore->toString();

        return "{$status} - Score: {$score} - {$this->primaryIndicator}";
    }
}
