<?php

declare(strict_types=1);

namespace App\Framework\Logging\Handlers;

use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Health\HealthCheckCategory;
use App\Framework\Logging\LogHandler;
use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;

/**
 * Buffered Log Handler für verbesserte Performance
 *
 * Sammelt Log-Einträge in einem Memory-Buffer und schreibt sie batch-weise.
 * Reduziert I/O-Operationen und verbessert die Performance erheblich.
 *
 * Features:
 * - Automatischer Flush bei Buffer-Größe
 * - Zeitbasierter Flush
 * - Sofortiger Flush für kritische Logs (ERROR, CRITICAL, etc.)
 * - Destruktor stellt sicher, dass alle Logs geschrieben werden
 */
final class BufferedLogHandler implements LogHandler, \App\Framework\Health\HealthCheckInterface
{
    /** @var LogRecord[] */
    private array $buffer = [];
    private Timestamp $lastFlushTime;

    public function __construct(
        private readonly LogHandler $handler,
        private readonly int $bufferSize = 100,
        private readonly float $flushIntervalSeconds = 5.0,
        private readonly bool $flushOnError = true
    ) {
        $this->lastFlushTime = Timestamp::now();
    }

    public function handle(LogRecord $record): void
    {
        $this->buffer[] = $record;

        // Sofortiger Flush bei Errors (wenn aktiviert)
        if ($this->flushOnError && $record->level->value >= LogLevel::ERROR->value) {
            $this->flush();
            return;
        }

        // Flush wenn Buffer voll
        if (count($this->buffer) >= $this->bufferSize) {
            $this->flush();
            return;
        }

        // Zeitbasierter Flush
        $now = Timestamp::now();
        if ($now->diffInSeconds($this->lastFlushTime) >= $this->flushIntervalSeconds) {
            $this->flush();
        }
    }

    /**
     * Schreibt alle gepufferten Logs
     */
    public function flush(): void
    {
        if (empty($this->buffer)) {
            return;
        }

        $records = $this->buffer;
        $count = count($records);
        $this->buffer = [];
        $this->lastFlushTime = Timestamp::now();

        // Report flush metrics
        if (class_exists(\App\Framework\Logging\Metrics\LogMetricsCollector::class)) {
            \App\Framework\Logging\Metrics\LogMetricsCollector::getInstance()
                ->recordBufferFlush('buffered', $count);
        }

        foreach ($records as $record) {
            try {
                $this->handler->handle($record);
            } catch (\Throwable $e) {
                // Bei Fehler: verbleibende Records wieder in Buffer
                // und Exception werfen (wird von ResilientHandler gefangen)
                $this->buffer = array_merge($records, $this->buffer);
                throw $e;
            }
        }
    }

    /**
     * Destruktor stellt sicher, dass alle Logs geschrieben werden
     */
    public function __destruct()
    {
        try {
            $this->flush();
        } catch (\Throwable) {
            // Silent fail im Destruktor
        }
    }

    public function getBufferSize(): int
    {
        return count($this->buffer);
    }

    public function isEmpty(): bool
    {
        return empty($this->buffer);
    }

    public function check(): \App\Framework\Health\HealthCheckResult
    {
        $bufferSize = $this->getBufferSize();
        $fillPercentage = ($bufferSize / $this->bufferSize) * 100;

        $details = [
            'buffer_size' => $bufferSize,
            'max_buffer_size' => $this->bufferSize,
            'fill_percentage' => round($fillPercentage, 2),
            'last_flush' => $this->lastFlushTime->format('Y-m-d H:i:s'),
            'seconds_since_last_flush' => Timestamp::now()->diffInSeconds($this->lastFlushTime),
        ];

        $status = \App\Framework\Health\HealthStatus::HEALTHY;
        $message = 'Buffer healthy';

        if ($fillPercentage >= 90) {
            $status = \App\Framework\Health\HealthStatus::DEGRADED;
            $message = sprintf('Buffer nearly full: %.1f%%', $fillPercentage);
        } elseif ($fillPercentage >= 75) {
            $status = \App\Framework\Health\HealthStatus::DEGRADED;
            $message = sprintf('Buffer filling up: %.1f%%', $fillPercentage);
        }

        return new \App\Framework\Health\HealthCheckResult(
            status: $status,
            componentName: $this->getName(),
            message: $message,
            details: $details,
            timestamp: new \DateTimeImmutable()
        );
    }

    public function getName(): string
    {
        return 'buffered_handler';
    }

    public function isHandling(LogRecord $record): bool
    {
        // Delegate to wrapped handler
        return $this->handler->isHandling($record);
    }

    public function getCategory(): HealthCheckCategory
    {
        return HealthCheckCategory::INFRASTRUCTURE;
    }

    public function getTimeout(): int
    {
        return 3000; // 3 seconds timeout for buffered handler health check
    }
}
