<?php

declare(strict_types=1);

namespace App\Framework\Logging\Handlers;

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

/**
 * Handler für die Ausgabe von Log-Einträgen in der Konsole.
 */
class ConsoleHandler implements LogHandler
{
    /**
     * @var LogLevel Minimales Level, ab dem dieser Handler aktiv wird
     */
    private LogLevel $minLevel;

    /**
     * @var bool Ob der Handler nur im Debug-Modus aktiv ist
     */
    private bool $debugOnly;

    /**
     * @var LogFormatter Formatter für die Log-Ausgabe
     */
    private LogFormatter $formatter;

    /**
     * Erstellt einen neuen ConsoleHandler
     *
     * @param LogFormatter $formatter Formatter für die Log-Ausgabe
     * @param LogLevel|int $minLevel Minimales Level, ab dem dieser Handler aktiv wird
     * @param bool $debugOnly Ob der Handler nur im Debug-Modus aktiv ist
     */
    public function __construct(
        LogFormatter $formatter,
        LogLevel|int $minLevel = LogLevel::DEBUG,
        bool $debugOnly = true,
        private readonly LogLevel $stderrLevel = LogLevel::WARNING,
    ) {
        $this->formatter = $formatter;
        $this->minLevel = $minLevel instanceof LogLevel ? $minLevel : LogLevel::fromValue($minLevel);
        $this->debugOnly = $debugOnly;
    }

    /**
     * Überprüft, ob dieser Handler den Log-Eintrag verarbeiten soll
     */
    public function isHandling(LogRecord $record): bool
    {
        // Nur im CLI-Modus aktiv - NIE bei Web-Requests!
        if (PHP_SAPI !== 'cli') {
            return false;
        }

        // Optional: Debug-Modus-Check nur in CLI
        if ($this->debugOnly && ! filter_var(getenv('APP_DEBUG'), FILTER_VALIDATE_BOOLEAN)) {
            return false;
        }


        return $record->getLevel()->value >= $this->minLevel->value;
    }

    /**
     * Verarbeitet einen Log-Eintrag
     */
    public function handle(LogRecord $record): void
    {
        // Formatter verwenden für Formatierung
        $formatted = ($this->formatter)($record);

        // Formatter gibt immer string zurück für Console
        $output = is_string($formatted)
            ? $formatted
            : json_encode($formatted, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

        // Stelle sicher, dass ein Newline vorhanden ist
        if (!str_ends_with($output, PHP_EOL)) {
            $output .= PHP_EOL;
        }

        // Fehler und Warnungen auf stderr, alles andere auf stdout
        if ($record->getLevel()->value >= $this->stderrLevel->value) {
            // WARNING, ERROR, CRITICAL, ALERT, EMERGENCY -> stderr
            file_put_contents('php://stderr', $output);
        } else {
            // DEBUG, INFO, NOTICE -> stdout
            echo $output;
        }
    }

    /**
     * Gibt den Formatter zurück
     */
    public function getFormatter(): LogFormatter
    {
        return $this->formatter;
    }

    /**
     * Minimales Log-Level setzen
     */
    public function setMinLevel(LogLevel|int $level): self
    {
        $this->minLevel = $level instanceof LogLevel ? $level : LogLevel::fromValue($level);

        return $this;
    }
}
