<?php

declare(strict_types=1);

namespace App\Framework\Performance\Examples;

use App\Framework\Performance\PerformanceMeter;
use App\Framework\Performance\PerformanceCategory;

/**
 * Beispiel-Event-Handler für Event-Performance-Tracking
 *
 * Dieser Handler zeigt, wie Performance-Messungen bei verschiedenen
 * Event-Typen implementiert werden können.
 */
class PerformanceEventHandlerExample
{
    private PerformanceMeter $meter;
    private array $activeEventMeasurements = [];
    private array $eventStatistics = [];
    private array $config;

    public function __construct(PerformanceMeter $meter, array $config = [])
    {
        $this->meter = $meter;
        $this->config = array_merge([
            'track_all_events' => true,
            'track_slow_events_only' => false,
            'slow_event_threshold_ms' => 100,
            'detailed_sub_measurements' => true,
            'enable_event_statistics' => true,
        ], $config);
    }

    /**
     * Event-Start-Handler - beginnt Performance-Tracking
     */
    public function onEventStart($event): void
    {
        $eventName = $this->getEventName($event);
        $eventId = $this->getEventId($event);
        $measurementId = "event_{$eventName}_{$eventId}";

        // Event-Start markieren
        $this->meter->mark("event_start_{$eventName}", PerformanceCategory::EVENT);

        // Hauptmessung für das Event starten
        $this->meter->startMeasure($measurementId, PerformanceCategory::EVENT);

        // Für spätere Referenz speichern
        $this->activeEventMeasurements[$eventId] = [
            'measurement_id' => $measurementId,
            'event_name' => $eventName,
            'start_time' => microtime(true),
            'start_memory' => memory_get_usage(true),
        ];

        // Event-spezifische Performance-Messungen
        $this->trackEventSpecificMetrics($event, $eventName);
    }

    /**
     * Event-Ende-Handler - beendet Performance-Tracking
     */
    public function onEventEnd($event): void
    {
        $eventId = $this->getEventId($event);

        if (!isset($this->activeEventMeasurements[$eventId])) {
            return; // Event wurde nicht getrackt
        }

        $measurement = $this->activeEventMeasurements[$eventId];
        $eventName = $measurement['event_name'];
        $measurementId = $measurement['measurement_id'];

        // Hauptmessung beenden
        $this->meter->endMeasure($measurementId);

        // Event-Ende markieren
        $this->meter->mark("event_end_{$eventName}", PerformanceCategory::EVENT);

        // Performance-Analyse
        $duration = (microtime(true) - $measurement['start_time']) * 1000;
        $memoryUsed = (memory_get_usage(true) - $measurement['start_memory']) / 1024 / 1024;

        // Statistiken aktualisieren
        if ($this->config['enable_event_statistics']) {
            $this->updateEventStatistics($eventName, $duration, $memoryUsed);
        }

        // Langsame Events kennzeichnen
        if ($duration > $this->config['slow_event_threshold_ms']) {
            $this->meter->mark("slow_event_{$eventName}", PerformanceCategory::EVENT);
            $this->handleSlowEvent($event, $duration);
        }

        // Performance-Daten ausgeben/loggen
        $this->logEventPerformance($event, $duration, $memoryUsed);

        // Cleanup
        unset($this->activeEventMeasurements[$eventId]);
    }

    /**
     * Spezifische Event-Handler mit detaillierten Messungen
     */
    public function handleUserRegistrationEvent($event): void
    {
        $this->meter->startMeasure('user_registration_processing', PerformanceCategory::USER);

        // Email-Validierung messen
        $this->meter->measure('email_validation', function() use ($event) {
            $this->validateUserEmail($event->getEmail());
        }, PerformanceCategory::VALIDATION);

        // Password-Hashing messen
        $this->meter->measure('password_hashing', function() use ($event) {
            $this->hashUserPassword($event->getPassword());
        }, PerformanceCategory::SECURITY);

        // Database-Insert messen
        $this->meter->measure('user_db_insert', function() use ($event) {
            $this->insertUserToDatabase($event->getUserData());
        }, PerformanceCategory::DATABASE);

        // Welcome-Email senden (async)
        $this->meter->measure('welcome_email_queue', function() use ($event) {
            $this->queueWelcomeEmail($event->getUser());
        }, PerformanceCategory::EXTERNAL);

        $this->meter->endMeasure('user_registration_processing');

        // Zusätzliche Marker für wichtige Schritte
        $this->meter->mark('user_registered', PerformanceCategory::USER);
    }

    /**
     * E-Commerce Order Event Handler
     */
    public function handleOrderCreatedEvent($event): void
    {
        $this->meter->startMeasure('order_processing', PerformanceCategory::BUSINESS);

        // Inventory-Check
        $this->meter->measure('inventory_check', function() use ($event) {
            $this->checkOrderInventory($event->getOrderItems());
        }, PerformanceCategory::DATABASE);

        // Payment-Processing
        $this->meter->measure('payment_processing', function() use ($event) {
            $this->processOrderPayment($event->getPaymentData());
        }, PerformanceCategory::EXTERNAL);

        // Tax-Calculation
        $this->meter->measure('tax_calculation', function() use ($event) {
            $this->calculateOrderTax($event->getOrder());
        }, PerformanceCategory::BUSINESS);

        // Order-Confirmation
        $this->meter->measure('order_confirmation', function() use ($event) {
            $this->sendOrderConfirmation($event->getOrder());
        }, PerformanceCategory::EXTERNAL);

        // Inventory-Update
        $this->meter->measure('inventory_update', function() use ($event) {
            $this->updateInventoryAfterOrder($event->getOrderItems());
        }, PerformanceCategory::DATABASE);

        $this->meter->endMeasure('order_processing');

        $this->meter->mark('order_completed', PerformanceCategory::BUSINESS);
    }

    /**
     * File-Upload Event Handler
     */
    public function handleFileUploadEvent($event): void
    {
        $this->meter->startMeasure('file_upload_processing', PerformanceCategory::FILE);

        $fileSize = $event->getFileSize();
        $fileName = $event->getFileName();

        // File-Validation
        $this->meter->measure('file_validation', function() use ($event) {
            $this->validateUploadedFile($event->getFile());
        }, PerformanceCategory::VALIDATION);

        // Virus-Scan (bei großen Files)
        if ($fileSize > 1024 * 1024) { // > 1MB
            $this->meter->measure('virus_scan', function() use ($event) {
                $this->scanFileForViruses($event->getFile());
            }, PerformanceCategory::SECURITY);
        }

        // File-Resize/Processing (bei Images)
        if ($this->isImage($fileName)) {
            $this->meter->measure('image_processing', function() use ($event) {
                $this->processUploadedImage($event->getFile());
            }, PerformanceCategory::FILE);
        }

        // File-Storage
        $this->meter->measure('file_storage', function() use ($event) {
            $this->storeFile($event->getFile(), $event->getStoragePath());
        }, PerformanceCategory::FILE);

        // Metadata-Extraction
        $this->meter->measure('metadata_extraction', function() use ($event) {
            $this->extractFileMetadata($event->getFile());
        }, PerformanceCategory::FILE);

        $this->meter->endMeasure('file_upload_processing');

        // File-Size-spezifische Marker
        if ($fileSize > 10 * 1024 * 1024) { // > 10MB
            $this->meter->mark('large_file_uploaded', PerformanceCategory::FILE);
        }
    }

    /**
     * Cache-Event Handler
     */
    public function handleCacheEvent($event): void
    {
        $operation = $event->getOperation(); // 'get', 'set', 'delete', 'flush'
        $cacheKey = $event->getCacheKey();

        $measurementId = "cache_{$operation}_{$cacheKey}";

        $result = $this->meter->measure($measurementId, function() use ($event) {
            return $this->executeCacheOperation($event);
        }, PerformanceCategory::CACHE);

        // Cache-Hit/Miss markieren
        if ($operation === 'get') {
            $hitMiss = $result !== null ? 'hit' : 'miss';
            $this->meter->mark("cache_{$hitMiss}_{$cacheKey}", PerformanceCategory::CACHE);
        }

        // Cache-Statistiken aktualisieren
        $this->updateCacheStatistics($operation, $cacheKey, $result);
    }

    /**
     * Event-spezifische Metriken tracken
     */
    private function trackEventSpecificMetrics($event, string $eventName): void
    {
        if (!$this->config['detailed_sub_measurements']) {
            return;
        }

        // Event-Serialization messen (falls Event serialisiert wird)
        if (method_exists($event, 'serialize')) {
            $this->meter->measure("event_serialization_{$eventName}", function() use ($event) {
                $event->serialize();
            }, PerformanceCategory::EVENT);
        }

        // Event-Validation messen
        if (method_exists($event, 'validate')) {
            $this->meter->measure("event_validation_{$eventName}", function() use ($event) {
                $event->validate();
            }, PerformanceCategory::VALIDATION);
        }

        // Listener-Count als Marker
        $listenerCount = $this->getListenerCount($eventName);
        if ($listenerCount > 5) {
            $this->meter->mark("many_listeners_{$eventName}", PerformanceCategory::EVENT);
        }
    }

    /**
     * Langsame Events behandeln
     */
    private function handleSlowEvent($event, float $duration): void
    {
        $eventName = $this->getEventName($event);

        // Warnung loggen
        error_log("SLOW EVENT WARNING: {$eventName} took {$duration}ms");

        // Detaillierte Informationen sammeln
        $report = $this->meter->generateReport();
        $slowOperations = [];

        foreach ($report['measurements'] as $label => $data) {
            if ($data['avg_time_ms'] > 50) { // Operationen > 50ms
                $slowOperations[] = "{$label}: {$data['avg_time_ms']}ms";
            }
        }

        if (!empty($slowOperations)) {
            error_log("SLOW EVENT DETAILS: " . implode(', ', $slowOperations));
        }

        // Für kritische Events: Alert senden
        if ($this->isCriticalEvent($eventName) && $duration > 1000) {
            $this->sendPerformanceAlert($eventName, $duration);
        }
    }

    /**
     * Event-Performance loggen
     */
    private function logEventPerformance($event, float $duration, float $memoryMb): void
    {
        $eventName = $this->getEventName($event);

        // Entscheidung: Wann loggen?
        $shouldLog = $this->config['track_all_events'] ||
                    ($this->config['track_slow_events_only'] && $duration > $this->config['slow_event_threshold_ms']);

        if (!$shouldLog) {
            return;
        }

        $logData = [
            'event_name' => $eventName,
            'event_id' => $this->getEventId($event),
            'duration_ms' => round($duration, 2),
            'memory_mb' => round($memoryMb, 2),
            'timestamp' => microtime(true),
        ];

        // Event-spezifische Daten hinzufügen
        if (method_exists($event, 'getLogData')) {
            $logData['event_data'] = $event->getLogData();
        }

        error_log('EVENT_PERFORMANCE: ' . json_encode($logData));
    }

    /**
     * Event-Statistiken aktualisieren
     */
    private function updateEventStatistics(string $eventName, float $duration, float $memory): void
    {
        if (!isset($this->eventStatistics[$eventName])) {
            $this->eventStatistics[$eventName] = [
                'count' => 0,
                'total_time_ms' => 0,
                'total_memory_mb' => 0,
                'min_time_ms' => PHP_FLOAT_MAX,
                'max_time_ms' => 0,
            ];
        }

        $stats = &$this->eventStatistics[$eventName];
        $stats['count']++;
        $stats['total_time_ms'] += $duration;
        $stats['total_memory_mb'] += $memory;
        $stats['min_time_ms'] = min($stats['min_time_ms'], $duration);
        $stats['max_time_ms'] = max($stats['max_time_ms'], $duration);
        $stats['avg_time_ms'] = $stats['total_time_ms'] / $stats['count'];
        $stats['avg_memory_mb'] = $stats['total_memory_mb'] / $stats['count'];
    }

    /**
     * Event-Statistiken abrufen
     */
    public function getEventStatistics(): array
    {
        return $this->eventStatistics;
    }

    /**
     * Performance-Bericht für alle Events
     */
    public function generateEventPerformanceReport(): string
    {
        $report = "EVENT PERFORMANCE STATISTICS\n";
        $report .= str_repeat('=', 50) . "\n";

        foreach ($this->eventStatistics as $eventName => $stats) {
            $report .= sprintf(
                "%-30s Count: %4d | Avg: %6.2fms | Min: %6.2fms | Max: %6.2fms | Mem: %5.2fMB\n",
                $eventName,
                $stats['count'],
                $stats['avg_time_ms'],
                $stats['min_time_ms'],
                $stats['max_time_ms'],
                $stats['avg_memory_mb']
            );
        }

        return $report;
    }

    // === HELPER-METHODEN ===

    private function getEventName($event): string
    {
        return get_class($event);
    }

    private function getEventId($event): string
    {
        return method_exists($event, 'getId') ? $event->getId() : uniqid();
    }

    private function getListenerCount(string $eventName): int
    {
        // Dummy-Implementation - in echter Anwendung würde hier
        // die Anzahl der registrierten Listener zurückgegeben
        return rand(1, 10);
    }

    private function isCriticalEvent(string $eventName): bool
    {
        $criticalEvents = [
            'OrderCreatedEvent',
            'PaymentProcessedEvent',
            'UserRegistrationEvent',
            'SecurityAlertEvent',
        ];

        return in_array(basename($eventName), $criticalEvents);
    }

    private function sendPerformanceAlert(string $eventName, float $duration): void
    {
        // Dummy - in echter Implementierung: Slack, Email, SMS, etc.
        error_log("CRITICAL PERFORMANCE ALERT: {$eventName} took {$duration}ms");
    }

    // === DUMMY-IMPLEMENTIERUNGEN FÜR VOLLSTÄNDIGE BEISPIELE ===

    private function validateUserEmail(string $email): bool
    {
        usleep(5000); // 5ms simulierte Email-Validierung
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    private function hashUserPassword(string $password): string
    {
        usleep(100000); // 100ms simuliertes Password-Hashing (realistisch)
        return password_hash($password, PASSWORD_DEFAULT);
    }

    private function insertUserToDatabase(array $userData): bool
    {
        usleep(25000); // 25ms simulierter DB-Insert
        return true;
    }

    private function queueWelcomeEmail($user): void
    {
        usleep(2000); // 2ms für Queue-Operation
    }

    private function checkOrderInventory(array $items): bool
    {
        usleep(15000); // 15ms simulierte Inventory-Prüfung
        return true;
    }

    private function processOrderPayment(array $paymentData): bool
    {
        usleep(200000); // 200ms simulierte Payment-Verarbeitung (realistisch)
        return true;
    }

    private function calculateOrderTax(array $order): float
    {
        usleep(10000); // 10ms simulierte Tax-Berechnung
        return 19.99;
    }

    private function sendOrderConfirmation(array $order): void
    {
        usleep(50000); // 50ms simulierte Email-Versendung
    }

    private function updateInventoryAfterOrder(array $items): void
    {
        usleep(20000); // 20ms simuliertes Inventory-Update
    }

    private function validateUploadedFile($file): bool
    {
        usleep(8000); // 8ms simulierte File-Validierung
        return true;
    }

    private function scanFileForViruses($file): bool
    {
        usleep(150000); // 150ms simulierter Virus-Scan
        return true;
    }

    private function isImage(string $fileName): bool
    {
        $imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
        $extension = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
        return in_array($extension, $imageExtensions);
    }

    private function processUploadedImage($file): void
    {
        usleep(75000); // 75ms simulierte Image-Verarbeitung
    }

    private function storeFile($file, string $path): bool
    {
        usleep(30000); // 30ms simulierte File-Storage
        return true;
    }

    private function extractFileMetadata($file): array
    {
        usleep(12000); // 12ms simulierte Metadata-Extraktion
        return ['size' => 1024, 'type' => 'image/jpeg'];
    }

    private function executeCacheOperation($event): mixed
    {
        $operation = $event->getOperation();
        $delay = [
            'get' => 2000,    // 2ms
            'set' => 5000,    // 5ms
            'delete' => 3000, // 3ms
            'flush' => 50000, // 50ms
        ];

        usleep($delay[$operation] ?? 1000);

        return $operation === 'get' ? (rand(0, 1) ? 'cached_value' : null) : true;
    }

    private function updateCacheStatistics(string $operation, string $key, $result): void
    {
        // Dummy - Cache-Statistiken würden hier aktualisiert
    }
}
