<?php

declare(strict_types=1);

namespace App\Framework\Performance\ValueObjects;

use App\Framework\Core\ValueObjects\Byte;
use App\Framework\Core\ValueObjects\Percentage;

/**
 * Value Object für Memory-Zusammenfassung
 */
final readonly class MemorySummary
{
    public function __construct(
        public Byte $current,
        public Byte $peak,
        public Byte $limit,
        public Percentage $usagePercentage,
        public bool $isApproachingLimit
    ) {
    }

    /**
     * Gibt die aktuelle Speichernutzung in Bytes zurück
     */
    public function getCurrentBytes(): int
    {
        return $this->current->toBytes();
    }

    /**
     * Gibt die Peak-Speichernutzung in Bytes zurück
     */
    public function getPeakBytes(): int
    {
        return $this->peak->toBytes();
    }

    /**
     * Gibt das Speicherlimit in Bytes zurück
     */
    public function getLimitBytes(): int
    {
        return $this->limit->toBytes();
    }

    /**
     * Gibt die aktuelle Speichernutzung human-readable zurück
     */
    public function getCurrentHumanReadable(): string
    {
        return $this->current->toHumanReadable();
    }

    /**
     * Gibt die Peak-Speichernutzung human-readable zurück
     */
    public function getPeakHumanReadable(): string
    {
        return $this->peak->toHumanReadable();
    }

    /**
     * Gibt das Speicherlimit human-readable zurück
     */
    public function getLimitHumanReadable(): string
    {
        return $this->limit->toHumanReadable();
    }

    /**
     * Gibt den Usage-Prozentsatz formatiert zurück
     */
    public function getUsagePercentageFormatted(int $decimals = 2): string
    {
        return $this->usagePercentage->format($decimals);
    }

    /**
     * Prüft ob der Speicher knapp wird (Standard: 80%)
     */
    public function isMemoryLow(float $threshold = 80.0): bool
    {
        return $this->usagePercentage->greaterThanOrEqual(Percentage::from($threshold));
    }

    /**
     * Prüft ob der Speicher kritisch knapp wird (Standard: 90%)
     */
    public function isMemoryCritical(float $threshold = 90.0): bool
    {
        return $this->usagePercentage->greaterThanOrEqual(Percentage::from($threshold));
    }

    /**
     * Gibt die verfügbare Speichermenge zurück
     */
    public function getAvailableMemory(): Byte
    {
        $availableBytes = $this->limit->toBytes() - $this->current->toBytes();

        return Byte::fromBytes(max(0, $availableBytes));
    }

    /**
     * Konvertiert zu Array (für Backward Compatibility)
     */
    public function toArray(): array
    {
        return [
            'current' => [
                'bytes' => $this->getCurrentBytes(),
                'human' => $this->getCurrentHumanReadable(),
            ],
            'peak' => [
                'bytes' => $this->getPeakBytes(),
                'human' => $this->getPeakHumanReadable(),
            ],
            'limit' => [
                'bytes' => $this->getLimitBytes(),
                'human' => $this->getLimitHumanReadable(),
            ],
            'available' => [
                'bytes' => $this->getAvailableMemory()->toBytes(),
                'human' => $this->getAvailableMemory()->toHumanReadable(),
            ],
            'usage_percentage' => $this->getUsagePercentageFormatted(),
            'is_approaching_limit' => $this->isApproachingLimit,
            'is_memory_low' => $this->isMemoryLow(),
            'is_memory_critical' => $this->isMemoryCritical(),
        ];
    }

    /**
     * String-Repräsentation für Debug-Zwecke
     */
    public function __toString(): string
    {
        return sprintf(
            'Memory: %s / %s (%s) | Peak: %s | Available: %s',
            $this->getCurrentHumanReadable(),
            $this->getLimitHumanReadable(),
            $this->getUsagePercentageFormatted(),
            $this->getPeakHumanReadable(),
            $this->getAvailableMemory()->toHumanReadable()
        );
    }

    /**
     * JSON-Serialisierung
     */
    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}
