<?php

declare(strict_types=1);

namespace App\Framework\ErrorHandling;

use App\Framework\Exception\SecurityException;
use App\Framework\Exception\ErrorHandlerContext;
use App\Framework\Exception\SecurityLogLevel;
use App\Framework\Logging\Logger;
use App\Framework\Logging\LogLevel;

/**
 * Spezialisierter Logger für Security-Events im OWASP-Format
 */
final readonly class SecurityEventLogger
{
    public function __construct(
        private ?Logger $logger = null,
        private string $applicationId = 'app'
    ) {}

    /**
     * Loggt Security-Event im OWASP-Format
     */
    public function logSecurityEvent(
        SecurityException $exception,
        ErrorHandlerContext $context
    ): void {
        $securityEvent = $exception->getSecurityEvent();

        // OWASP-konformes Log generieren
        $owaspLog = $this->createOWASPLog($exception, $context);

        if ($this->logger) {
            // Strukturiertes Logging über Framework Logger
            $frameworkLogLevel = $this->mapSecurityLevelToFrameworkLevel($securityEvent->getLogLevel());

            $this->logger->log(
                $frameworkLogLevel,
                $securityEvent->getDescription(),
                [
                    'security_event' => $securityEvent->getEventIdentifier(),
                    'security_category' => $securityEvent->getCategory(),
                    'requires_alert' => $securityEvent->requiresAlert(),
                    'owasp_format' => $owaspLog,
                    'event_data' => $securityEvent->toArray(),
                    'context_data' => $context->forLogging()
                ]
            );
        } else {
            // Fallback auf error_log
            $this->logToErrorLog($owaspLog);
        }
    }

    /**
     * Loggt kritische Security-Alerts
     */
    public function logCriticalAlert(
        SecurityException $exception,
        ErrorHandlerContext $context
    ): void {
        $alertData = $this->createAlertData($exception, $context);

        if ($this->logger) {
            $this->logger->log(
                LogLevel::CRITICAL,
                'SECURITY_ALERT: ' . $exception->getSecurityEvent()->getEventIdentifier(),
                $alertData
            );
        } else {
            error_log('SECURITY_ALERT: ' . json_encode($alertData));
        }
    }

    /**
     * Erstellt OWASP-konformes Log-Format
     */
    private function createOWASPLog(
        SecurityException $exception,
        ErrorHandlerContext $context
    ): array {
        $securityEvent = $exception->getSecurityEvent();

        return [
            'datetime' => date('c'),
            'appid' => $this->applicationId,
            'event' => $securityEvent->getEventIdentifier(),
            'level' => $securityEvent->getLogLevel()->value,
            'description' => $securityEvent->getDescription(),
            'useragent' => $context->request->userAgent,
            'source_ip' => $context->request->clientIp,
            'host_ip' => $context->request->hostIp,
            'hostname' => $context->request->hostname,
            'protocol' => $context->request->protocol,
            'port' => $context->request->port,
            'request_uri' => $context->request->requestUri,
            'request_method' => $context->request->requestMethod,
            'region' => $_ENV['AWS_REGION'] ?? 'unknown',
            'geo' => $_ENV['GEO_LOCATION'] ?? 'unknown',
            'category' => $securityEvent->getCategory(),
            'requires_alert' => $securityEvent->requiresAlert()
        ];
    }

    /**
     * Erstellt Alert-Daten für kritische Events
     */
    private function createAlertData(
        SecurityException $exception,
        ErrorHandlerContext $context
    ): array {
        return [
            'event' => $exception->getSecurityEvent()->getEventIdentifier(),
            'description' => $exception->getSecurityEvent()->getDescription(),
            'level' => $exception->getSecurityLevel()->value,
            'category' => $exception->getSecurityEvent()->getCategory(),
            'client_ip' => $context->request->clientIp,
            'user_agent' => $context->request->userAgent,
            'request_uri' => $context->request->requestUri,
            'request_method' => $context->request->requestMethod,
            'timestamp' => date('c'),
            'request_id' => $context->request->requestId,
            'event_data' => $exception->getSecurityEvent()->toArray()
        ];
    }

    /**
     * Fallback-Logging über error_log
     */
    private function logToErrorLog(array $owaspLog): void
    {
        $logMessage = 'SECURITY_EVENT: ' . json_encode($owaspLog, JSON_UNESCAPED_SLASHES);
        error_log($logMessage);
    }

    /**
     * Mappt SecurityLogLevel auf Framework LogLevel
     */
    private function mapSecurityLevelToFrameworkLevel(
        SecurityLogLevel $securityLevel
    ): LogLevel {
        return match($securityLevel) {
            SecurityLogLevel::DEBUG => LogLevel::DEBUG,
            SecurityLogLevel::INFO => LogLevel::INFO,
            SecurityLogLevel::WARN => LogLevel::WARNING,
            SecurityLogLevel::ERROR => LogLevel::ERROR,
            SecurityLogLevel::FATAL => LogLevel::CRITICAL,
        };
    }

    /**
     * Factory-Methode für Standard-Konfiguration
     */
    public static function create(?Logger $logger = null): self
    {
        return new self(
            $logger,
            $_ENV['APP_NAME'] ?? $_ENV['APP_ID'] ?? 'app'
        );
    }
}
