<?php

declare(strict_types=1);

namespace App\Framework\Performance;

use App\Framework\Core\PathProvider;
use App\Framework\DateTime\Clock;
use App\Framework\Jobs\JobQueue;

class PerformanceFileLogger
{
    private array $buffer = [];
    private string $logFile;
    private Clock $clock;
    private ?JobQueue $jobQueue;
    private array $config;

    public function __construct(
        PathProvider $pathProvider,
        Clock $clock,
        ?JobQueue $jobQueue = null,
        array $config = []
    ) {
        $this->clock = $clock;
        $this->jobQueue = $jobQueue;
        $this->config = array_merge([
            'buffer_size' => 50,
            'flush_interval' => 300, // 5 Minuten
            'min_threshold_ms' => 0,
            'background_processing' => true,
            'include_request_data' => true,
        ], $config);

        $logDir = $pathProvider->getStoragePath('logs/performance');
        $this->ensureLogDirectory($logDir);

        $date = $this->clock->now()->format('Y-m-d');
        $this->logFile = "{$logDir}/performance-{$date}.jsonl";

        // Cleanup bei Script-Ende
        register_shutdown_function([$this, 'shutdown']);
    }

    public function log(PerformanceMeter $meter, array $context = []): void
    {
        $report = $meter->generateReport();

        // Schwellenwert prüfen
        if ($report['summary']['total_time_ms'] < $this->config['min_threshold_ms']) {
            return;
        }

        $data = [
            'timestamp' => $this->clock->now()->format('c'),
            'timestamp_float' => $this->clock->microtime(),
            'request_id' => $this->generateRequestId(),
            'url' => $_SERVER['REQUEST_URI'] ?? 'cli',
            'method' => $_SERVER['REQUEST_METHOD'] ?? 'CLI',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'CLI',
            'memory_peak_mb' => memory_get_peak_usage(true) / 1024 / 1024,
            'performance' => $report,
            'context' => $context,
        ];

        if ($this->config['include_request_data']) {
            $data['server_data'] = $this->getServerData();
        }

        // In Buffer schreiben (extrem schnell)
        $this->buffer[] = $data;

        // Bei Puffergröße verarbeiten
        if (count($this->buffer) >= $this->config['buffer_size']) {
            $this->flushBuffer();
        }
    }

    private function flushBuffer(): void
    {
        if (empty($this->buffer)) {
            return;
        }

        // Schnell in File schreiben
        $content = '';
        foreach ($this->buffer as $entry) {
            $content .= json_encode($entry, JSON_UNESCAPED_SLASHES) . "\n";
        }

        file_put_contents($this->logFile, $content, FILE_APPEND | LOCK_EX);

        // Background-Verarbeitung anstoßen
        if ($this->config['background_processing'] && $this->jobQueue) {
            $this->scheduleBackgroundProcessing();
        }

        $this->buffer = [];
    }

    private function scheduleBackgroundProcessing(): void
    {
        // Job für die Verarbeitung in die Queue einreihen
        $this->jobQueue->dispatch(new ProcessPerformanceLogsJob($this->logFile));
    }

    private function getServerData(): array
    {
        return [
            'php_version' => PHP_VERSION,
            'memory_limit' => ini_get('memory_limit'),
            'max_execution_time' => ini_get('max_execution_time'),
            'server_name' => $_SERVER['SERVER_NAME'] ?? 'unknown',
            'remote_addr' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
        ];
    }

    private function generateRequestId(): string
    {
        return uniqid('req_', true);
    }

    private function ensureLogDirectory(string $directory): void
    {
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }
    }

    public function shutdown(): void
    {
        $this->flushBuffer();
    }

    public function getLogFile(): string
    {
        return $this->logFile;
    }

    public function setEnabled(bool $enabled): void
    {
        $this->config['enabled'] = $enabled;
    }

    public function isEnabled(): bool
    {
        return $this->config['enabled'] ?? true;
    }

    /**
     * Bereinigt alte Log-Dateien
     */
    public function cleanup(int $retentionDays = 30): void
    {
        if ($retentionDays <= 0) {
            return;
        }

        $cutoffTime = $this->clock->now()->getTimestamp() - ($retentionDays * 24 * 3600);
        $logDir = dirname($this->logFile);
        $files = glob($logDir . '/performance-*.jsonl');

        foreach ($files as $file) {
            if (filemtime($file) < $cutoffTime) {
                unlink($file);
            }
        }
    }
}
