<?php

declare(strict_types=1);

namespace App\Framework\Debug;

/**
 * Repräsentiert einen einzelnen Debug-Eintrag mit allen relevanten Informationen.
 */
final class DebugEntry
{
    /** @var \DateTimeImmutable */
    private \DateTimeImmutable $timestamp;

    /** @var string */
    private string $memory;

    /** @var string */
    private string $peakMemory;

    /**
     * Erstellt einen neuen Debug-Eintrag
     */
    public function __construct(
        private readonly mixed  $data,
        private readonly string $label,
        private readonly string $file,
        private readonly int    $line,
        private readonly EntryType $type = EntryType::STANDARD
    ) {
        $this->timestamp = new \DateTimeImmutable(timezone: new \DateTimeZone('Europe/Berlin'));
        $this->memory = self::formatBytes(memory_get_usage(true));
        $this->peakMemory = self::formatBytes(memory_get_peak_usage(true));
    }

    /**
     * Gibt die Debug-Daten zurück
     */
    public function getData(): mixed
    {
        return $this->data;
    }

    /**
     * Gibt das Label zurück
     */
    public function getLabel(): string
    {
        return $this->label;
    }

    /**
     * Gibt den Pfad der Datei zurück
     */
    public function getFile(): string
    {
        return $this->file;
    }

    /**
     * Gibt die Zeilennummer zurück
     */
    public function getLine(): int
    {
        return $this->line;
    }

    /**
     * Gibt den Dateinamen ohne Pfad zurück
     */
    public function getFilename(): string
    {
        return basename($this->file);
    }

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

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

    /**
     * Gibt den aktuellen Speicherverbrauch zurück
     */
    public function getMemory(): string
    {
        return $this->memory;
    }

    /**
     * Gibt den höchsten Speicherverbrauch zurück
     */
    public function getPeakMemory(): string
    {
        return $this->peakMemory;
    }

    /**
     * Gibt den Typ des Eintrags zurück
     */
    public function getType(): EntryType
    {
        return $this->type;
    }

    /**
     * Erstellt ein Array mit allen Debug-Daten
     */
    public function toArray(): array
    {
        return [
            'data' => $this->data,
            'label' => $this->label,
            'file' => $this->file,
            'line' => $this->line,
            'timestamp' => $this->getFormattedTimestamp(),
            'memory' => $this->memory,
            'peak_memory' => $this->peakMemory,
            'type' => $this->type->name,
        ];
    }

    /**
     * Formatiert Bytes in lesbare Größen
     */
    private static function formatBytes(int $bytes): string
    {
        $units = ['B', 'KB', 'MB', 'GB'];
        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= (1 << (10 * $pow));

        return round($bytes, 2) . ' ' . $units[$pow];
    }
}
