<?php
declare(strict_types=1);

namespace App\Framework\Logging\Handlers;

use App\Framework\Logging\LogHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;

/**
 * Handler für Syslog-basiertes Logging
 */
final class SyslogHandler implements LogHandler
{
    private bool $isOpen = false;

    public function __construct(
        private readonly string   $ident = 'php-app',
        private readonly int      $facility = LOG_USER,
        private readonly LogLevel $minLevel = LogLevel::DEBUG
    ) {}

    public function isHandling(LogRecord $record): bool
    {
        return $record->getLevel()->value >= $this->minLevel->value;
    }

    public function handle(LogRecord $record): void
    {
        $this->openSyslog();

        $priority = $this->mapLogLevelToSyslogPriority($record->getLevel());
        $message = $this->formatMessage($record);

        syslog($priority, $message);
    }

    private function openSyslog(): void
    {
        if (!$this->isOpen) {
            openlog($this->ident, LOG_PID | LOG_PERROR, $this->facility);
            $this->isOpen = true;
        }
    }

    private function formatMessage(LogRecord $record): string
    {
        $parts = [];

        // Request-ID falls vorhanden
        if ($record->hasExtra('request_id')) {
            $parts[] = "[{$record->getExtra('request_id')}]";
        }

        // Channel falls vorhanden
        if ($record->getChannel()) {
            $parts[] = "[{$record->getChannel()}]";
        }

        // Hauptnachricht
        $parts[] = $record->getMessage();

        // Context-Daten falls vorhanden
        $context = $record->getContext();
        if (!empty($context)) {
            $parts[] = 'Context: ' . json_encode($context, JSON_UNESCAPED_SLASHES);
        }

        return implode(' ', $parts);
    }

    /**
     * Mappt Framework LogLevel auf Syslog-Prioritäten
     */
    private function mapLogLevelToSyslogPriority(LogLevel $level): int
    {
        return match ($level) {
            LogLevel::EMERGENCY => LOG_EMERG,
            LogLevel::ALERT => LOG_ALERT,
            LogLevel::CRITICAL => LOG_CRIT,
            LogLevel::ERROR => LOG_ERR,
            LogLevel::WARNING => LOG_WARNING,
            LogLevel::NOTICE => LOG_NOTICE,
            LogLevel::INFO => LOG_INFO,
            LogLevel::DEBUG => LOG_DEBUG,
        };
    }

    public function __destruct()
    {
        if ($this->isOpen) {
            closelog();
        }
    }
}
