<?php

declare(strict_types=1);

namespace App\Framework\Waf\ValueObjects;

use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\Http\IpAddress;
use App\Framework\UserAgent\UserAgent;

/**
 * Metadata associated with WAF layer results
 */
final readonly class ResultMetadata
{
    public function __construct(
        public ?Percentage $confidence = null,
        public ?RuleId $ruleId = null,
        public ?string $attackVector = null,
        public ?IpAddress $sourceIp = null,
        public ?UserAgent $userAgent = null,
        public ?PayloadSample $payloadSample = null,
        public ?AdditionalContext $context = null
    ) {
    }

    /**
     * Create empty metadata
     */
    public static function empty(): self
    {
        return new self();
    }

    /**
     * Create metadata with confidence level
     */
    public static function withConfidence(Percentage $confidence): self
    {
        return new self(confidence: $confidence);
    }

    /**
     * Create metadata with rule information
     */
    public static function withRule(RuleId $ruleId, ?Percentage $confidence = null): self
    {
        return new self(
            confidence: $confidence,
            ruleId: $ruleId
        );
    }

    /**
     * Create metadata with attack vector information
     */
    public static function withAttackVector(
        string $attackVector,
        ?RuleId $ruleId = null,
        ?Percentage $confidence = null
    ): self {
        return new self(
            confidence: $confidence,
            ruleId: $ruleId,
            attackVector: $attackVector
        );
    }

    /**
     * Create metadata with request context
     */
    public static function withRequestContext(
        IpAddress $sourceIp,
        UserAgent $userAgent,
        ?PayloadSample $payloadSample = null
    ): self {
        return new self(
            sourceIp: $sourceIp,
            userAgent: $userAgent,
            payloadSample: $payloadSample
        );
    }

    /**
     * Check if metadata has confidence information
     */
    public function hasConfidence(): bool
    {
        return $this->confidence !== null;
    }

    /**
     * Check if metadata has rule information
     */
    public function hasRule(): bool
    {
        return $this->ruleId !== null;
    }

    /**
     * Check if metadata has attack vector information
     */
    public function hasAttackVector(): bool
    {
        return $this->attackVector !== null;
    }

    /**
     * Check if metadata has request context
     */
    public function hasRequestContext(): bool
    {
        return $this->sourceIp !== null || $this->userAgent !== null;
    }

    /**
     * Merge with another metadata object
     */
    public function merge(self $other): self
    {
        return new self(
            confidence: $other->confidence ?? $this->confidence,
            ruleId: $other->ruleId ?? $this->ruleId,
            attackVector: $other->attackVector ?? $this->attackVector,
            sourceIp: $other->sourceIp ?? $this->sourceIp,
            userAgent: $other->userAgent ?? $this->userAgent,
            payloadSample: $other->payloadSample ?? $this->payloadSample,
            context: $other->context?->merge($this->context) ?? $this->context
        );
    }

    /**
     * Add payload sample
     */
    public function withPayloadSample(PayloadSample $sample): self
    {
        return new self(
            confidence: $this->confidence,
            ruleId: $this->ruleId,
            attackVector: $this->attackVector,
            sourceIp: $this->sourceIp,
            userAgent: $this->userAgent,
            payloadSample: $sample,
            context: $this->context
        );
    }

    /**
     * Add additional context
     */
    public function withContext(AdditionalContext $context): self
    {
        return new self(
            confidence: $this->confidence,
            ruleId: $this->ruleId,
            attackVector: $this->attackVector,
            sourceIp: $this->sourceIp,
            userAgent: $this->userAgent,
            payloadSample: $this->payloadSample,
            context: $context
        );
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return array_filter([
            'confidence' => $this->confidence?->getValue(),
            'rule_id' => $this->ruleId?->value,
            'attack_vector' => $this->attackVector,
            'source_ip' => $this->sourceIp?->value,
            'user_agent' => $this->userAgent?->value,
            'payload_sample' => $this->payloadSample?->toArray(),
            'context' => $this->context?->toArray(),
        ], fn ($value) => $value !== null);
    }
}
