<?php

declare(strict_types=1);

namespace App\Framework\Waf;

use App\Framework\Config\WafConfig;
use App\Framework\DateTime\Clock;
use App\Framework\DI\Container;
use App\Framework\DI\Initializer;
use App\Framework\Logging\Logger;
use App\Framework\Logging\ValueObjects\LogContext;
use App\Framework\Performance\PerformanceService;
use App\Framework\Waf\Layers\CommandInjectionLayer;
use App\Framework\Waf\Layers\PathTraversalLayer;
use App\Framework\Waf\Layers\SqlInjectionLayer;
use App\Framework\Waf\Layers\SuspiciousUserAgentLayer;
use App\Framework\Waf\Layers\XssLayer;
use App\Framework\Waf\MachineLearning\MachineLearningEngine;

/**
 * WAF Engine Initializer
 *
 * Registers security layers with the WAF Engine during framework startup.
 * This enables proper threat detection by configuring all available security layers.
 */
final readonly class WafEngineInitializer
{
    private WafEngine $wafEngine;

    private Logger $logger;

    public function __construct(
        private Container $container
    ) {
        $this->wafEngine = new WafEngine(
            WafConfig::development(),
            $this->container->get(ThreatAssessmentService::class),
            $this->container->get(PerformanceService::class),
            $this->container->get(Logger::class),
            $this->container->get(Clock::class),
            $this->container->get(MachineLearningEngine::class)
        );
        $this->logger = $this->container->get(Logger::class);
    }

    /**
     * Initialize WAF Engine with all security layers
     */
    #[Initializer]
    public function __invoke(): WafEngine
    {
        $this->logger->info('Initializing WAF Engine with security layers');

        try {
            // Register core security layers in priority order
            $this->registerSecurityLayers();

            $this->logger->info('WAF Engine initialized successfully', LogContext::withData([
                'registered_layers' => $this->getRegisteredLayerNames(),
                'health_status' => $this->wafEngine->getHealthStatus(),
            ]));

        } catch (\Throwable $e) {
            $this->logger->error('Failed to initialize WAF Engine', LogContext::withData([
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]));

            // Re-throw to prevent application startup with broken WAF
            throw $e;
        }

        return $this->wafEngine;
    }

    /**
     * Register all security layers with the WAF Engine
     */
    private function registerSecurityLayers(): void
    {
        // High priority layers (processed first)
        $this->wafEngine->registerLayer(new SqlInjectionLayer());
        $this->wafEngine->registerLayer(new CommandInjectionLayer());
        $this->wafEngine->registerLayer(new PathTraversalLayer());

        // Medium priority layers
        $this->wafEngine->registerLayer(new XssLayer());

        // Low priority layers (processed last)
        $this->wafEngine->registerLayer(new SuspiciousUserAgentLayer());

        $this->logger->debug('Security layers registered', LogContext::withData([
            'layers_count' => count($this->getRegisteredLayerNames()),
        ]));
    }

    /**
     * Get names of registered layers for logging
     * @return string[]
     */
    private function getRegisteredLayerNames(): array
    {
        // Since WafEngine doesn't expose layer names, we'll return what we registered
        return [
            'sql_injection',
            'command_injection',
            'path_traversal',
            'xss',
            'suspicious_user_agent',
        ];
    }
}
