<?php
declare(strict_types=1);

namespace App\Framework\Logging\Handlers;

use App\Framework\Console\ConsoleColor;
use App\Framework\Logging\LogHandler;
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 string Format für die Ausgabe
     */
    private string $outputFormat;

    /**
     * Erstellt einen neuen ConsoleHandler
     *
     * @param LogLevel|int $minLevel Minimales Level, ab dem dieser Handler aktiv wird
     * @param bool $debugOnly Ob der Handler nur im Debug-Modus aktiv ist
     * @param string $outputFormat Format für die Ausgabe
     */
    public function __construct(
        LogLevel|int $minLevel = LogLevel::DEBUG,
        bool $debugOnly = true,
        string $outputFormat = '{color}[{level_name}]{reset} {timestamp} {request_id}{message}',
        private LogLevel $stderrLevel = LogLevel::WARNING,
    ) {
        $this->minLevel = $minLevel instanceof LogLevel ? $minLevel : LogLevel::fromValue($minLevel);
        $this->debugOnly = $debugOnly;
        $this->outputFormat = $outputFormat;
    }

    /**
     * Ü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
    {
        $logLevel = $record->getLevel();
        $color = $logLevel->getConsoleColor()->value;
        $reset = ConsoleColor::RESET->value;

        // Request-ID-Teil erstellen, falls vorhanden
        $requestId = $record->hasExtra('request_id')
            ? "[{$record->getExtra('request_id')}] "
            : '';

        // Werte für Platzhalter im Format
        $values = [
            '{color}' => $color,
            '{reset}' => $reset,
            '{level_name}' => $record->getLevel()->getName(),
            '{timestamp}' => $record->getFormattedTimestamp(),
            '{request_id}' => $requestId,
            '{message}' => $record->getMessage(),
            '{channel}' => $record->getChannel() ? "[{$record->getChannel()}] " : '',
        ];

        // Formatierte Ausgabe erstellen
        $output = strtr($this->outputFormat, $values) . 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;
        }
    }

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

    /**
     * Ausgabeformat setzen
     */
    public function setOutputFormat(string $format): self
    {
        $this->outputFormat = $format;
        return $this;
    }
}
