<?php

declare(strict_types=1);

namespace App\Framework\Exception;

use App\Framework\Http\MiddlewareContext;

/**
 * Vollständiger Kontext für Error-Handling - kombiniert alle Kontext-Typen
 */
final readonly class ErrorHandlerContext
{
    public function __construct(
        public ExceptionContext $exception,
        public RequestContext $request,
        public SystemContext $system,
        public array $metadata = []
    ) {}

    public static function create(
        ExceptionContext $exceptionContext,
        ?RequestContext $requestContext = null,
        ?SystemContext $systemContext = null,
        array $metadata = []
    ): self {
        return new self(
            exception: $exceptionContext,
            request: $requestContext ?? RequestContext::fromGlobals(),
            system: $systemContext ?? SystemContext::current(),
            metadata: $metadata
        );
    }

    public static function fromException(\Throwable $exception, array $metadata = []): self
    {
        $exceptionContext = ExceptionContext::empty();

        if ($exception instanceof FrameworkException) {
            $exceptionContext = $exception->getContext();
        }

        return self::create($exceptionContext, metadata: $metadata);
    }

    public function withMetadata(array $metadata): self
    {
        return new self(
            exception: $this->exception,
            request: $this->request,
            system: $this->system,
            metadata: array_merge($this->metadata, $metadata)
        );
    }

    public function withRequest(RequestContext $request): self
    {
        return new self(
            exception: $this->exception,
            request: $request,
            system: $this->system,
            metadata: $this->metadata
        );
    }

    public function withSystem(SystemContext $system): self
    {
        return new self(
            exception: $this->exception,
            request: $this->request,
            system: $system,
            metadata: $this->metadata
        );
    }

    public function toArray(): array
    {
        return [
            'exception' => $this->exception->toArray(),
            'request' => $this->request->toArray(),
            'system' => $this->system->toArray(),
            'metadata' => $this->metadata
        ];
    }

    /**
     * Gibt eine flache Struktur zurück für einfache Serialisierung
     */
    public function toFlatArray(): array
    {
        $contexts = [
            'exception' => $this->exception->toArray(),
            'request' => $this->request->toArray(),
            'system' => $this->system->toArray()
        ];

        $flattened = [];
        foreach ($contexts as $prefix => $data) {
            array_walk($data, function($value, $key) use (&$flattened, $prefix) {
                $flattened[$prefix . '_' . $key] = $value;
            });
        }

        return array_merge($flattened, $this->metadata);
    }

    /**
     * Extrahiert nur relevante Daten für Logging
     */
    public function forLogging(): array
    {
        return [
            'operation' => $this->exception->operation,
            'component' => $this->exception->component,
            'client_ip' => $this->request->clientIp,
            'request_method' => $this->request->requestMethod,
            'request_uri' => $this->request->requestUri,
            'memory_usage' => $this->system->memoryUsage,
            'execution_time' => $this->system->executionTime,
            'data' => $this->exception->data,
            'metadata' => $this->metadata
        ];
    }

    /**
     * Generiert Security-Event-Log im OWASP-Format
     */
    public function toSecurityEventFormat(string $appId = 'app'): array
    {
        $exceptionData = $this->exception->toArray();

        // Basis-Format
        $securityLog = [
            'datetime' => date('c'),
            'appid' => $appId,
            'level' => 'INFO',
            'description' => 'No description',
            'useragent' => $this->request->userAgent,
            'source_ip' => $this->request->clientIp,
            'host_ip' => $this->request->hostIp,
            'hostname' => $this->request->hostname,
            'protocol' => $this->request->protocol,
            'port' => $this->request->port,
            'request_uri' => $this->request->requestUri,
            'request_method' => $this->request->requestMethod,
            'region' => $_ENV['AWS_REGION'] ?? 'unknown',
            'geo' => $_ENV['GEO_LOCATION'] ?? 'unknown'
        ];

        // Security-Event-spezifische Daten falls verfügbar
        if (isset($exceptionData['metadata']['security_event'])) {
            $securityLog['event'] = $exceptionData['metadata']['security_event'];
            $securityLog['level'] = $exceptionData['metadata']['security_level'] ?? 'INFO';
            $securityLog['description'] = $exceptionData['metadata']['security_description'] ?? 'Security event';
        } else {
            // Fallback für normale Exceptions
            $securityLog['event'] = 'application_error';
            $securityLog['level'] = 'ERROR';
            $securityLog['description'] = 'Application error occurred';
        }

        return $securityLog;
    }

    /**
     * Generiert JSON für Security-Event-Log
     */
    public function toSecurityEventJson(string $appId = 'app'): string
    {
        return json_encode($this->toSecurityEventFormat($appId), JSON_UNESCAPED_SLASHES);
    }

    /**
     * Factory-Methode um ErrorHandlerContext aus Exception zu erstellen
     */
    /*public static function fromException(Throwable $exception, ?MiddlewareContext $middlewareContext = null): self
    {
        // Request-Context aufbauen
        $requestContext = RequestContext::create(
            clientIp: $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            userAgent: $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            requestMethod: $_SERVER['REQUEST_METHOD'] ?? 'CLI',
            requestUri: $_SERVER['REQUEST_URI'] ?? '-',
            hostIp: $_SERVER['SERVER_ADDR'] ?? 'unknown',
            hostname: $_SERVER['HTTP_HOST'] ?? 'localhost',
            protocol: $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.1',
            port: $_SERVER['SERVER_PORT'] ?? '80',
            requestId: $middlewareContext?->requestId ?? bin2hex(random_bytes(8))
        );

        // Exception-Context
        $exceptionContext = ExceptionContext::fromThrowable($exception);

        // System-Context
        $systemContext = SystemContext::create(
            memoryUsage: memory_get_usage(true),
            peakMemoryUsage: memory_get_peak_usage(true),
            executionTime: microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true))
        );

        return new self(
            exception: $exceptionContext,
            request: $requestContext,
            system: $systemContext,
            metadata: []
        );
    }*/
}
