<?php
declare(strict_types=1);

namespace App\Framework\Logging;

/**
 * Repräsentiert einen einzelnen Log-Eintrag mit allen relevanten Informationen.
 */
final class LogRecord
{
    /**
     * @var array<string, mixed> Zusätzliche Daten, die dynamisch hinzugefügt werden können
     */
    private array $extra = [];

    /**
     * Erstellt einen neuen Log-Eintrag
     */
    public function __construct(
        private string $message,
        private array $context,
        private LogLevel $level,
        private \DateTimeImmutable $timestamp,
        private ?string $channel = null
    ) {}

    /**
     * Gibt die Log-Nachricht zurück
     */
    public function getMessage(): string
    {
        return $this->message;
    }

    /**
     * Setzt die Log-Nachricht
     */
    public function setMessage(string $message): self
    {
        $this->message = $message;
        return $this;
    }

    /**
     * Gibt den Kontext zurück
     */
    public function getContext(): array
    {
        return $this->context;
    }

    /**
     * Setzt oder erweitert den Kontext
     */
    public function withContext(array $context): self
    {
        $this->context = array_merge($this->context, $context);
        return $this;
    }

    /**
     * Gibt das Log-Level zurück
     */
    public function getLevel(): LogLevel
    {
        return $this->level;
    }

    /**
     * Gibt den Zeitstempel zurück
     */
    public function getTimestamp(): \DateTimeImmutable
    {
        return $this->timestamp;
    }

    /**
     * Gibt den formattierten Zeitstempel zurück
     */
    public function getFormattedTimestamp(string $format = 'Y-m-d H:i:s'): string
    {
        return $this->timestamp->format($format);
    }

    /**
     * Gibt den Kanal zurück, falls gesetzt
     */
    public function getChannel(): ?string
    {
        return $this->channel;
    }

    /**
     * Setzt den Kanal
     */
    public function setChannel(string $channel): self
    {
        $this->channel = $channel;
        return $this;
    }

    /**
     * Fügt einen Wert zu den Extra-Daten hinzu
     */
    public function addExtra(string $key, mixed $value): self
    {
        $this->extra[$key] = $value;
        return $this;
    }

    /**
     * Fügt mehrere Extra-Daten hinzu
     */
    public function addExtras(array $extras): self
    {
        foreach ($extras as $key => $value) {
            $this->extra[$key] = $value;
        }
        return $this;
    }

    /**
     * Prüft, ob ein bestimmter Extra-Wert existiert
     */
    public function hasExtra(string $key): bool
    {
        return array_key_exists($key, $this->extra);
    }

    /**
     * Gibt einen Extra-Wert zurück
     */
    public function getExtra(string $key, mixed $default = null): mixed
    {
        return $this->extra[$key] ?? $default;
    }

    /**
     * Gibt alle Extra-Daten zurück
     */
    public function getExtras(): array
    {
        return $this->extra;
    }

    /**
     * Erstellt ein Array mit allen Log-Daten
     */
    public function toArray(): array
    {
        return [
            'message' => $this->message,
            'context' => $this->context,
            'level' => $this->level->value,
            'level_name' => $this->level->getName(),
            'timestamp' => $this->getFormattedTimestamp(),
            'datetime' => $this->timestamp,
            'channel' => $this->channel,
            'extra' => $this->extra,
        ];
    }
}
