<?php

declare(strict_types=1);

namespace App\Framework\Waf\ValueObjects;

use App\Framework\Core\ValueObjects\Duration;
use App\Framework\Core\ValueObjects\Percentage;

/**
 * Configuration for WAF layers
 * Immutable configuration object with validation
 */
final readonly class LayerConfig
{
    public function __construct(
        public bool $enabled = true,
        public ?Duration $timeout = null,
        public ?Percentage $confidenceThreshold = null,
        public bool $blockingMode = true,
        public bool $logDetections = true,
        public int $maxDetectionsPerRequest = 100,
        public array $customSettings = []
    ) {
    }

    /**
     * Create default configuration
     */
    public static function default(): self
    {
        return new self(
            enabled: true,
            timeout: Duration::fromSeconds(5),
            confidenceThreshold: Percentage::from(70.0),
            blockingMode: true,
            logDetections: true,
            maxDetectionsPerRequest: 100
        );
    }

    /**
     * Create production configuration (stricter)
     */
    public static function production(): self
    {
        return new self(
            enabled: true,
            timeout: Duration::fromSeconds(3),
            confidenceThreshold: Percentage::from(85.0),
            blockingMode: true,
            logDetections: true,
            maxDetectionsPerRequest: 50
        );
    }

    /**
     * Create development configuration (more permissive)
     */
    public static function development(): self
    {
        return new self(
            enabled: true,
            timeout: Duration::fromSeconds(10),
            confidenceThreshold: Percentage::from(50.0),
            blockingMode: false, // Log only in development
            logDetections: true,
            maxDetectionsPerRequest: 200
        );
    }

    /**
     * Create testing configuration
     */
    public static function testing(): self
    {
        return new self(
            enabled: true,
            timeout: Duration::fromSeconds(1),
            confidenceThreshold: Percentage::from(1.0), // Very low threshold for testing
            blockingMode: false,
            logDetections: false, // Reduce noise in tests
            maxDetectionsPerRequest: 1000
        );
    }

    /**
     * Enable layer
     */
    public function enable(): self
    {
        return new self(
            enabled: true,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Disable layer
     */
    public function disable(): self
    {
        return new self(
            enabled: false,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Set timeout
     */
    public function withTimeout(Duration $timeout): self
    {
        return new self(
            enabled: $this->enabled,
            timeout: $timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Set confidence threshold
     */
    public function withConfidenceThreshold(Percentage $threshold): self
    {
        return new self(
            enabled: $this->enabled,
            timeout: $this->timeout,
            confidenceThreshold: $threshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Enable/disable blocking mode
     */
    public function withBlockingMode(bool $blockingMode): self
    {
        return new self(
            enabled: $this->enabled,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Enable/disable detection logging
     */
    public function withLogging(bool $logDetections): self
    {
        return new self(
            enabled: $this->enabled,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $this->customSettings
        );
    }

    /**
     * Set maximum detections per request
     */
    public function withMaxDetections(int $maxDetections): self
    {
        return new self(
            enabled: $this->enabled,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $maxDetections,
            customSettings: $this->customSettings
        );
    }

    /**
     * Add custom setting
     */
    public function withCustomSetting(string $key, mixed $value): self
    {
        $customSettings = $this->customSettings;
        $customSettings[$key] = $value;

        return new self(
            enabled: $this->enabled,
            timeout: $this->timeout,
            confidenceThreshold: $this->confidenceThreshold,
            blockingMode: $this->blockingMode,
            logDetections: $this->logDetections,
            maxDetectionsPerRequest: $this->maxDetectionsPerRequest,
            customSettings: $customSettings
        );
    }

    /**
     * Get custom setting value
     */
    public function getCustomSetting(string $key, mixed $default = null): mixed
    {
        return $this->customSettings[$key] ?? $default;
    }

    /**
     * Check if custom setting exists
     */
    public function hasCustomSetting(string $key): bool
    {
        return array_key_exists($key, $this->customSettings);
    }

    /**
     * Get effective timeout with fallback
     */
    public function getEffectiveTimeout(): Duration
    {
        return $this->timeout ?? Duration::fromSeconds(5);
    }

    /**
     * Get effective confidence threshold with fallback
     */
    public function getEffectiveConfidenceThreshold(): Percentage
    {
        return $this->confidenceThreshold ?? Percentage::from(70.0);
    }

    /**
     * Validate configuration
     */
    public function validate(): array
    {
        $errors = [];

        if ($this->timeout !== null && $this->timeout->toSeconds() <= 0) {
            $errors[] = 'Timeout must be greater than 0 seconds';
        }

        if ($this->timeout !== null && $this->timeout->toSeconds() > 60) {
            $errors[] = 'Timeout should not exceed 60 seconds';
        }

        if ($this->maxDetectionsPerRequest <= 0) {
            $errors[] = 'Max detections per request must be greater than 0';
        }

        if ($this->maxDetectionsPerRequest > 10000) {
            $errors[] = 'Max detections per request should not exceed 10000';
        }

        return $errors;
    }

    /**
     * Check if configuration is valid
     */
    public function isValid(): bool
    {
        return empty($this->validate());
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return [
            'enabled' => $this->enabled,
            'timeout_seconds' => $this->timeout?->toSeconds(),
            'confidence_threshold' => $this->confidenceThreshold?->getValue(),
            'blocking_mode' => $this->blockingMode,
            'log_detections' => $this->logDetections,
            'max_detections_per_request' => $this->maxDetectionsPerRequest,
            'custom_settings' => $this->customSettings,
        ];
    }
}
