<?php
declare(strict_types=1);

namespace App\Application\Security;

use App\Application\Security\ValueObjects\{
    SecurityContext,
    RequestContext,
    OWASPLogFormat,
    OWASPLogLevel
};
use App\Framework\Core\Events\OnEvent;
use Psr\Log\LoggerInterface;
use Throwable;

final class OWASPSecurityEventLogger
{
    public function __construct(
        private LoggerInterface $logger,
        private string $applicationId = 'app.security'
    ) {}

    /**
     * Universeller Event-Handler für alle OWASP Security Events
     */
    #[OnEvent]
    public function logSecurityEvent(OWASPSecurityEvent $event): void
    {
        try {
            $securityContext = SecurityContext::fromGlobals();
            $requestContext = RequestContext::fromGlobals();

            $owaspLogFormat = $this->createOWASPLogFormat(
                $event,
                $securityContext,
                $requestContext
            );

            // OWASP-konformes JSON-Log
            $this->logger->log(
                $this->mapLogLevel($event->getOWASPLogLevel()),
                $event->getDescription(),
                [
                    'owasp_format' => $owaspLogFormat->toArray(),
                    'event_class' => $event::class,
                    'event_data' => $event->getEventData()
                ]
            );

        } catch (Throwable $e) {
            // Fallback logging - niemals Security-Events verlieren
            $this->logger->critical('AUDIT_audit_failure:owasp_logger', [
                'datetime' => date('c'),
                'appid' => $this->applicationId,
                'event' => 'AUDIT_audit_failure:owasp_logger',
                'level' => 'FATAL',
                'description' => 'OWASP security event logging failed: ' . $e->getMessage(),
                'original_event_class' => $event::class,
                'error_trace' => $e->getTraceAsString()
            ]);
        }
    }

    private function createOWASPLogFormat(
        OWASPSecurityEvent $event,
        SecurityContext $securityContext,
        RequestContext $requestContext
    ): OWASPLogFormat {
        return OWASPLogFormat::create(
            $this->applicationId,
            $event->getOWASPEventIdentifier()->toString(),
            $event->getOWASPLogLevel()->value,
            $event->getDescription(),
            $securityContext,
            $requestContext
        );
    }

    private function mapLogLevel(OWASPLogLevel $owaspLevel): string
    {
        return match ($owaspLevel) {
            OWASPLogLevel::DEBUG => 'debug',
            OWASPLogLevel::INFO => 'info',
            OWASPLogLevel::WARN => 'warning',
            OWASPLogLevel::ERROR => 'error',
            OWASPLogLevel::FATAL => 'critical'
        };
    }
}
