<?php

declare(strict_types=1);

namespace App\Framework\ErrorHandling\View;

use App\Framework\Exception\ErrorHandlerContext;

/**
 * Renderer für API-Fehler im JSON-Format
 */
final readonly class ApiErrorRenderer implements ErrorViewRendererInterface
{
    /**
     * Rendert einen API-Fehler als JSON basierend auf ErrorHandlerContext
     */
    public function renderFromHandlerContext(ErrorHandlerContext $context, bool $isDebug = false): string
    {
        $responseData = [
            'error' => true,
            'code' => $context->metadata['http_status'] ?? 500,
            'message' => $this->getUserMessage($context, $isDebug),
            'requestId' => $context->request->requestId,
            'timestamp' => date('c'),
        ];

        // Exception-spezifische Daten hinzufügen
        if ($errorCode = $this->getErrorCode($context)) {
            $responseData['errorCode'] = $errorCode;
        }

        // Security Event Informationen (nur für interne Zwecke)
        if ($context->exception->metadata['security_event'] ?? false) {
            $responseData['type'] = 'security_event';

            if (! $isDebug) {
                // In Production keine Details von Security Events preisgeben
                $responseData['message'] = 'Invalid request. Please check your input and try again.';
            }
        }

        // Rate Limit spezifische Informationen
        if (isset($context->metadata['additional_headers']['X-RateLimit-Limit'])) {
            $responseData['rateLimit'] = [
                'limit' => (int) $context->metadata['additional_headers']['X-RateLimit-Limit'],
                'remaining' => (int) $context->metadata['additional_headers']['X-RateLimit-Remaining'],
                'reset' => (int) $context->metadata['additional_headers']['X-RateLimit-Reset'],
                'retryAfter' => (int) ($context->metadata['additional_headers']['Retry-After'] ?? 0),
            ];
        }

        // Debug-Informationen
        if ($isDebug) {
            $responseData['debug'] = [
                'operation' => $context->exception->operation,
                'component' => $context->exception->component,
                'exception_class' => $context->metadata['exception_class'],
                'client_ip' => $context->request->clientIp,
                'request_method' => $context->request->requestMethod,
                'request_uri' => $context->request->requestUri,
                'user_agent' => $context->request->userAgent,
                'memory_usage' => $context->system->memoryUsage ?? 0,
                'execution_time' => $context->system->executionTime ?? 0,
            ];

            // Exception-spezifische Debug-Daten
            if (! empty($context->exception->data)) {
                $responseData['debug']['exception_data'] = $context->exception->data;
            }

            if (! empty($context->exception->debug)) {
                $responseData['debug']['exception_debug'] = $context->exception->debug;
            }
        }

        return json_encode($responseData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }

    /**
     * Extrahiert benutzerfreundliche Nachricht aus ErrorHandlerContext
     */
    private function getUserMessage(ErrorHandlerContext $context, bool $isDebug): string
    {
        // Bei Debug-Modus die technische Nachricht verwenden
        if ($isDebug && isset($context->exception->data['exception_message'])) {
            return $context->exception->data['exception_message'];
        }

        // Exception-spezifische Nachrichten verwenden falls verfügbar
        if (isset($context->exception->data['user_message'])) {
            return $context->exception->data['user_message'];
        }

        // Fallback auf generische Nachrichten basierend auf HTTP-Status
        return match ($context->metadata['http_status'] ?? 500) {
            400 => 'Bad Request: Invalid input provided.',
            401 => 'Unauthorized: Authentication required.',
            403 => 'Forbidden: Insufficient permissions.',
            404 => 'Not Found: The requested resource was not found.',
            413 => 'Payload Too Large: Request size exceeds limit.',
            415 => 'Unsupported Media Type: Invalid content type.',
            423 => 'Locked: Account or resource is temporarily locked.',
            429 => 'Too Many Requests: Rate limit exceeded.',
            500 => 'Internal Server Error: An unexpected error occurred.',
            default => 'An error occurred while processing your request.',
        };
    }

    /**
     * Extrahiert Error-Code aus ErrorHandlerContext
     */
    private function getErrorCode(ErrorHandlerContext $context): ?string
    {
        // Aus Exception-Daten extrahieren
        if (isset($context->exception->data['error_code'])) {
            return $context->exception->data['error_code'];
        }

        // Aus Metadata extrahieren
        if (isset($context->exception->metadata['error_code'])) {
            return $context->exception->metadata['error_code'];
        }

        return null;
    }
}
