<?php

declare(strict_types=1);

namespace App\Framework\Waf\Analysis;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Waf\DetectionSeverity;

/**
 * Result of a single analysis operation
 */
final readonly class AnalysisResult
{
    public function __construct(
        public AnalysisType $type,
        public bool $passed,
        public DetectionSeverity $severity,
        public string $message,
        public array $findings = [],
        public array $metadata = [],
        public ?Duration $processingTime = null,
        public ?Timestamp $timestamp = null,
        public ?Percentage $confidence = null,
        public ?string $recommendation = null
    ) {
    }

    /**
     * Create successful analysis result
     */
    public static function success(
        AnalysisType $type,
        string $message = 'Analysis passed',
        array $metadata = []
    ): self {
        return new self(
            type: $type,
            passed: true,
            severity: DetectionSeverity::INFO,
            message: $message,
            findings: [],
            metadata: $metadata,
            timestamp: Timestamp::now(),
            confidence: Percentage::from(100.0)
        );
    }

    /**
     * Create failed analysis result
     */
    public static function failure(
        AnalysisType $type,
        DetectionSeverity $severity,
        string $message,
        array $findings = [],
        array $metadata = [],
        ?string $recommendation = null
    ): self {
        return new self(
            type: $type,
            passed: false,
            severity: $severity,
            message: $message,
            findings: $findings,
            metadata: $metadata,
            timestamp: Timestamp::now(),
            confidence: Percentage::from(85.0),
            recommendation: $recommendation
        );
    }

    /**
     * Create warning result (passed but with concerns)
     */
    public static function warning(
        AnalysisType $type,
        string $message,
        array $findings = [],
        array $metadata = [],
        ?string $recommendation = null
    ): self {
        return new self(
            type: $type,
            passed: true,
            severity: DetectionSeverity::LOW,
            message: $message,
            findings: $findings,
            metadata: $metadata,
            timestamp: Timestamp::now(),
            confidence: Percentage::from(70.0),
            recommendation: $recommendation
        );
    }

    /**
     * Create analysis result with custom confidence
     */
    public static function withConfidence(
        AnalysisType $type,
        bool $passed,
        DetectionSeverity $severity,
        string $message,
        Percentage $confidence,
        array $findings = [],
        array $metadata = []
    ): self {
        return new self(
            type: $type,
            passed: $passed,
            severity: $severity,
            message: $message,
            findings: $findings,
            metadata: $metadata,
            timestamp: Timestamp::now(),
            confidence: $confidence
        );
    }

    /**
     * Add processing time
     */
    public function withProcessingTime(Duration $processingTime): self
    {
        return new self(
            type: $this->type,
            passed: $this->passed,
            severity: $this->severity,
            message: $this->message,
            findings: $this->findings,
            metadata: $this->metadata,
            processingTime: $processingTime,
            timestamp: $this->timestamp,
            confidence: $this->confidence,
            recommendation: $this->recommendation
        );
    }

    /**
     * Add metadata
     */
    public function withMetadata(array $metadata): self
    {
        return new self(
            type: $this->type,
            passed: $this->passed,
            severity: $this->severity,
            message: $this->message,
            findings: $this->findings,
            metadata: array_merge($this->metadata, $metadata),
            processingTime: $this->processingTime,
            timestamp: $this->timestamp,
            confidence: $this->confidence,
            recommendation: $this->recommendation
        );
    }

    /**
     * Check if result indicates a security threat
     */
    public function isThreat(): bool
    {
        return ! $this->passed && ($this->severity === DetectionSeverity::HIGH ||
                                  $this->severity === DetectionSeverity::CRITICAL);
    }

    /**
     * Check if result should block request
     */
    public function shouldBlock(): bool
    {
        return $this->isThreat() &&
               ($this->confidence === null || $this->confidence->getValue() >= 80.0);
    }

    /**
     * Check if result should trigger alert
     */
    public function shouldAlert(): bool
    {
        return ! $this->passed &&
               $this->severity !== DetectionSeverity::INFO &&
               ($this->confidence === null || $this->confidence->getValue() >= 60.0);
    }

    /**
     * Get risk score (0-100)
     */
    public function getRiskScore(): float
    {
        if ($this->passed) {
            return 0.0;
        }

        $severityScore = match ($this->severity) {
            DetectionSeverity::CRITICAL => 100.0,
            DetectionSeverity::HIGH => 80.0,
            DetectionSeverity::MEDIUM => 60.0,
            DetectionSeverity::LOW => 30.0,
            DetectionSeverity::INFO => 10.0
        };

        // Apply confidence modifier
        if ($this->confidence !== null) {
            $severityScore *= ($this->confidence->getValue() / 100.0);
        }

        return $severityScore;
    }

    /**
     * Get finding count by type
     */
    public function getFindingCount(?string $type = null): int
    {
        if ($type === null) {
            return count($this->findings);
        }

        return count(array_filter(
            $this->findings,
            fn (array $finding) => ($finding['type'] ?? '') === $type
        ));
    }

    /**
     * Get findings by type
     */
    public function getFindingsByType(string $type): array
    {
        return array_filter(
            $this->findings,
            fn (array $finding) => ($finding['type'] ?? '') === $type
        );
    }

    /**
     * Check if analysis exceeded expected processing time
     */
    public function exceededExpectedTime(): bool
    {
        if ($this->processingTime === null) {
            return false;
        }

        $maxTime = $this->type->getMaxProcessingTime();

        return $this->processingTime->toMilliseconds() > $maxTime;
    }

    /**
     * Get performance assessment
     */
    public function getPerformanceAssessment(): string
    {
        if ($this->processingTime === null) {
            return 'unknown';
        }

        $maxTime = $this->type->getMaxProcessingTime();
        $actualTime = $this->processingTime->toMilliseconds();

        $ratio = $actualTime / $maxTime;

        return match (true) {
            $ratio <= 0.5 => 'excellent',
            $ratio <= 1.0 => 'good',
            $ratio <= 2.0 => 'acceptable',
            $ratio <= 5.0 => 'slow',
            default => 'critical'
        };
    }

    /**
     * Get summary text
     */
    public function getSummary(): string
    {
        $status = $this->passed ? 'PASS' : 'FAIL';
        $typeDesc = $this->type->getDescription();

        return "{$status}: {$typeDesc} - {$this->message}";
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'type' => $this->type->value,
            'type_description' => $this->type->getDescription(),
            'passed' => $this->passed,
            'severity' => $this->severity->value,
            'message' => $this->message,
            'findings' => $this->findings,
            'finding_count' => $this->getFindingCount(),
            'metadata' => $this->metadata,
            'processing_time_ms' => $this->processingTime?->toMilliseconds(),
            'timestamp' => $this->timestamp?->toIsoString(),
            'confidence' => $this->confidence?->getValue(),
            'recommendation' => $this->recommendation,
            'is_threat' => $this->isThreat(),
            'should_block' => $this->shouldBlock(),
            'should_alert' => $this->shouldAlert(),
            'risk_score' => $this->getRiskScore(),
            'exceeded_expected_time' => $this->exceededExpectedTime(),
            'performance_assessment' => $this->getPerformanceAssessment(),
            'summary' => $this->getSummary(),
        ];
    }
}
