<?php

declare(strict_types=1);

namespace App\Framework\Waf\Feedback;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Waf\DetectionCategory;
use App\Framework\Waf\DetectionSeverity;

/**
 * Represents feedback for a WAF detection
 */
final readonly class DetectionFeedback
{
    /**
     * @param string $detectionId ID of the detection this feedback is for
     * @param FeedbackType $feedbackType Type of feedback (false positive, false negative, etc.)
     * @param string $userId ID of the user who submitted the feedback
     * @param string|null $comment Optional comment provided with the feedback
     * @param Timestamp $timestamp When the feedback was submitted
     * @param DetectionCategory $category Category of the detection
     * @param DetectionSeverity $severity Severity of the detection
     * @param array<string, mixed> $context Additional context information
     */
    public function __construct(
        public string $detectionId,
        public FeedbackType $feedbackType,
        public string $userId,
        public ?string $comment,
        public Timestamp $timestamp,
        public DetectionCategory $category,
        public DetectionSeverity $severity,
        public array $context = []
    ) {
    }

    /**
     * Creates feedback for a false positive detection
     */
    public static function falsePositive(
        string $detectionId,
        string $userId,
        ?string $comment,
        DetectionCategory $category,
        DetectionSeverity $severity,
        array $context = []
    ): self {
        return new self(
            $detectionId,
            FeedbackType::FALSE_POSITIVE,
            $userId,
            $comment,
            Timestamp::now(),
            $category,
            $severity,
            $context
        );
    }

    /**
     * Creates feedback for a false negative detection
     */
    public static function falseNegative(
        string $detectionId,
        string $userId,
        ?string $comment,
        DetectionCategory $category,
        DetectionSeverity $severity,
        array $context = []
    ): self {
        return new self(
            $detectionId,
            FeedbackType::FALSE_NEGATIVE,
            $userId,
            $comment,
            Timestamp::now(),
            $category,
            $severity,
            $context
        );
    }

    /**
     * Creates feedback for a correct detection
     */
    public static function correctDetection(
        string $detectionId,
        string $userId,
        ?string $comment,
        DetectionCategory $category,
        DetectionSeverity $severity,
        array $context = []
    ): self {
        return new self(
            $detectionId,
            FeedbackType::CORRECT_DETECTION,
            $userId,
            $comment,
            Timestamp::now(),
            $category,
            $severity,
            $context
        );
    }

    /**
     * Creates feedback for a severity adjustment
     */
    public static function severityAdjustment(
        string $detectionId,
        string $userId,
        ?string $comment,
        DetectionCategory $category,
        DetectionSeverity $currentSeverity,
        DetectionSeverity $suggestedSeverity,
        array $context = []
    ): self {
        $contextWithSuggestion = array_merge($context, [
            'suggested_severity' => $suggestedSeverity->value,
        ]);

        return new self(
            $detectionId,
            FeedbackType::SEVERITY_ADJUSTMENT,
            $userId,
            $comment,
            Timestamp::now(),
            $category,
            $currentSeverity,
            $contextWithSuggestion
        );
    }

    /**
     * Gets the suggested severity for a severity adjustment feedback
     */
    public function getSuggestedSeverity(): ?DetectionSeverity
    {
        if ($this->feedbackType !== FeedbackType::SEVERITY_ADJUSTMENT) {
            return null;
        }

        $suggestedSeverityValue = $this->context['suggested_severity'] ?? null;

        if ($suggestedSeverityValue === null) {
            return null;
        }

        return DetectionSeverity::from($suggestedSeverityValue);
    }
}
