<?php
declare(strict_types=1);

namespace App\Framework\ErrorHandling;

use App\Framework\Logging\Logger;
use App\Framework\Logging\LogLevel;

/**
 * Logger für Fehler und Exceptions - nutzt Framework Logger
 */
final readonly class ErrorLogger
{
    public function __construct(
        private ?Logger $logger = null
    ) {}

    /**
     * Loggt einen Fehler basierend auf dem ErrorContext
     */
    public function logError(ErrorContext $context): void
    {
        $exception = $context->exception;
        $message = sprintf(
            '[%s] %s: %s in %s:%d',
            $context->requestId,
            get_class($exception),
            $exception->getMessage(),
            $exception->getFile(),
            $exception->getLine()
        );

        $contextData = [
            'exception' => $exception,
            'trace' => $exception->getTraceAsString(),
            'requestId' => $context->requestId,
            'additionalData' => $context->additionalData
        ];

        if ($this->logger !== null) {
            $logLevel = $this->mapErrorLevelToFrameworkLevel($context->level);
            $this->logger->log($logLevel, $message, $contextData);
        } else {
            // Fallback auf error_log
            $this->logToErrorLog($context);
        }
    }


    /**
     * Fallback-Methode für Logging ohne Framework Logger
     */
    private function logToErrorLog(ErrorContext $context): void
    {
        $exception = $context->exception;
        $message = sprintf(
            '[%s] [%s] %s: %s in %s:%d',
            date('Y-m-d H:i:s'),
            $context->level->name,
            get_class($exception),
            $exception->getMessage(),
            $exception->getFile(),
            $exception->getLine()
        );

        error_log($message);

        // Bei kritischen Fehlern auch den Stacktrace loggen
        if ($context->level === ErrorLevel::CRITICAL) {
            error_log("Stack trace: \n" . $exception->getTraceAsString());
        }
    }

    /**
     * Mappt interne ErrorLevel auf Framework LogLevel
     */
    private function mapErrorLevelToFrameworkLevel(ErrorLevel $level): LogLevel
    {
        return match($level) {
            ErrorLevel::CRITICAL => LogLevel::CRITICAL,
            ErrorLevel::ERROR => LogLevel::ERROR,
            ErrorLevel::WARNING => LogLevel::WARNING,
            ErrorLevel::NOTICE => LogLevel::NOTICE,
            ErrorLevel::INFO => LogLevel::INFO,
            ErrorLevel::DEBUG => LogLevel::DEBUG,
        };
    }
}
