<?php

declare(strict_types=1);

namespace App\Framework\Performance\Examples;

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

/**
 * Beispiel-Middleware für HTTP-Request Performance-Tracking
 *
 * Diese Middleware zeigt, wie Performance-Messungen in einer typischen
 * HTTP-Request-Pipeline implementiert werden können.
 */
class PerformanceMiddlewareExample
{
    private PerformanceMeter $meter;
    private array $config;

    public function __construct(PerformanceMeter $meter, array $config = [])
    {
        $this->meter = $meter;
        $this->config = array_merge([
            'track_all_requests' => true,
            'track_slow_requests_only' => false,
            'slow_threshold_ms' => 1000,
            'add_response_headers' => true,
            'detailed_measurement' => true,
        ], $config);
    }

    /**
     * Hauptmethode der Middleware - umschließt den Request-Prozess
     */
    public function handle($request, callable $next)
    {
        // === REQUEST START TRACKING ===
        $this->meter->mark('request_received', PerformanceCategory::FRAMEWORK);

        $startMemory = memory_get_usage(true);
        $requestId = $this->generateRequestId();

        // Request-Kontext für spätere Analyse sammeln
        $requestContext = $this->captureRequestContext($request);

        // === PRE-PROCESSING MEASUREMENT ===
        $this->meter->startMeasure('request_preprocessing', PerformanceCategory::FRAMEWORK);
        $this->preprocessRequest($request);
        $this->meter->endMeasure('request_preprocessing');

        // === AUTHENTICATION MEASUREMENT ===
        if ($this->shouldTrackAuth($request)) {
            $this->meter->startMeasure('authentication', PerformanceCategory::SECURITY);
            $authResult = $this->authenticateRequest($request);
            $this->meter->endMeasure('authentication');

            $this->meter->mark('auth_completed', PerformanceCategory::SECURITY);
        }

        // === AUTHORIZATION MEASUREMENT ===
        if ($this->shouldTrackAuthz($request)) {
            $this->meter->startMeasure('authorization', PerformanceCategory::SECURITY);
            $authzResult = $this->authorizeRequest($request);
            $this->meter->endMeasure('authorization');

            if (!$authzResult) {
                $this->meter->mark('authorization_failed', PerformanceCategory::SECURITY);
            }
        }

        // === CORE REQUEST PROCESSING ===
        $this->meter->mark('core_processing_start', PerformanceCategory::FRAMEWORK);
        $this->meter->startMeasure('core_request_processing', PerformanceCategory::CONTROLLER);

        // Hier würde der eigentliche Request-Handler aufgerufen
        $response = $next($request);

        $this->meter->endMeasure('core_request_processing');
        $this->meter->mark('core_processing_end', PerformanceCategory::FRAMEWORK);

        // === RESPONSE PROCESSING MEASUREMENT ===
        $this->meter->startMeasure('response_processing', PerformanceCategory::FRAMEWORK);
        $response = $this->processResponse($response, $requestContext);
        $this->meter->endMeasure('response_processing');

        // === LOGGING & CLEANUP MEASUREMENT ===
        $this->meter->startMeasure('logging_cleanup', PerformanceCategory::FRAMEWORK);
        $this->logRequestMetrics($requestId, $requestContext, $startMemory);
        $this->meter->endMeasure('logging_cleanup');

        // === FINAL MARKERS ===
        $this->meter->mark('request_completed', PerformanceCategory::FRAMEWORK);

        // === PERFORMANCE HEADERS HINZUFÜGEN ===
        if ($this->config['add_response_headers']) {
            $this->addPerformanceHeaders($response);
        }

        // === PERFORMANCE-DATEN AUSGEBEN/LOGGEN ===
        $this->outputPerformanceData($requestId, $requestContext);

        return $response;
    }

    /**
     * Request-Preprocessing mit detaillierter Messung
     */
    private function preprocessRequest($request): void
    {
        // Input-Validierung messen
        $this->meter->measure('input_validation', function() use ($request) {
            $this->validateInput($request);
        }, PerformanceCategory::VALIDATION);

        // Request-Parsing messen
        $this->meter->measure('request_parsing', function() use ($request) {
            $this->parseRequestData($request);
        }, PerformanceCategory::FRAMEWORK);

        // Rate-Limiting prüfen
        $this->meter->measure('rate_limiting', function() use ($request) {
            $this->checkRateLimit($request);
        }, PerformanceCategory::SECURITY);
    }

    /**
     * Authentication mit Performance-Tracking
     */
    private function authenticateRequest($request): bool
    {
        // Session-Check
        $sessionValid = $this->meter->measure('session_validation', function() use ($request) {
            return $this->validateSession($request);
        }, PerformanceCategory::SECURITY);

        if ($sessionValid) {
            $this->meter->mark('session_auth_success', PerformanceCategory::SECURITY);
            return true;
        }

        // Token-Authentication
        $tokenValid = $this->meter->measure('token_validation', function() use ($request) {
            return $this->validateToken($request);
        }, PerformanceCategory::SECURITY);

        if ($tokenValid) {
            $this->meter->mark('token_auth_success', PerformanceCategory::SECURITY);
            return true;
        }

        // Database-Authentication (langsam)
        $dbAuth = $this->meter->measure('database_authentication', function() use ($request) {
            return $this->authenticateAgainstDatabase($request);
        }, PerformanceCategory::DATABASE);

        if ($dbAuth) {
            $this->meter->mark('db_auth_success', PerformanceCategory::SECURITY);
        } else {
            $this->meter->mark('auth_failed', PerformanceCategory::SECURITY);
        }

        return $dbAuth;
    }

    /**
     * Response-Processing mit Messungen
     */
    private function processResponse($response, array $context)
    {
        // Content-Transformation
        $this->meter->measure('content_transformation', function() use ($response) {
            $this->transformResponseContent($response);
        }, PerformanceCategory::VIEW);

        // Caching-Headers setzen
        $this->meter->measure('cache_headers', function() use ($response, $context) {
            $this->setCacheHeaders($response, $context);
        }, PerformanceCategory::CACHE);

        // Compression
        if ($this->shouldCompress($response)) {
            $this->meter->measure('response_compression', function() use ($response) {
                $this->compressResponse($response);
            }, PerformanceCategory::FRAMEWORK);
        }

        return $response;
    }

    /**
     * Performance-Headers zum Response hinzufügen
     */
    private function addPerformanceHeaders($response): void
    {
        $report = $this->meter->generateReport();

        // Basis-Performance-Daten
        $response->headers['X-Performance-Time'] = sprintf('%.2fms', $report['summary']['total_time_ms']);
        $response->headers['X-Performance-Memory'] = sprintf('%.2fMB', $report['summary']['total_memory_mb']);
        $response->headers['X-Performance-Markers'] = (string) $report['summary']['marker_count'];

        // Detaillierte Kategorie-Zeiten
        foreach ($report['categories'] as $category => $data) {
            if (isset($data['total_time_ms'])) {
                $headerName = 'X-Performance-' . ucfirst($category);
                $response->headers[$headerName] = sprintf('%.2fms', $data['total_time_ms']);
            }
        }

        // Langsame Operationen hervorheben
        $slowOperations = $this->findSlowOperations($report);
        if (!empty($slowOperations)) {
            $response->headers['X-Performance-Slow-Ops'] = implode(',', $slowOperations);
        }

        // Memory-Peak
        $response->headers['X-Performance-Memory-Peak'] = sprintf('%.2fMB', memory_get_peak_usage(true) / 1024 / 1024);
    }

    /**
     * Performance-Daten ausgeben oder loggen
     */
    private function outputPerformanceData(string $requestId, array $context): void
    {
        $report = $this->meter->generateReport();
        $totalTime = $report['summary']['total_time_ms'];

        // Entscheidung: Wann sollen Performance-Daten ausgegeben werden?
        $shouldOutput = $this->config['track_all_requests'] ||
                       ($this->config['track_slow_requests_only'] && $totalTime > $this->config['slow_threshold_ms']);

        if (!$shouldOutput) {
            return;
        }

        // Für Development: Detaillierte Ausgabe
        if ($this->isDebugMode()) {
            echo "\n" . str_repeat('=', 50) . "\n";
            echo "PERFORMANCE REPORT - Request: $requestId\n";
            echo str_repeat('=', 50) . "\n";
            echo $this->meter->generateTextReport();
            echo str_repeat('=', 50) . "\n\n";
        }

        // Für Production: Strukturiertes Logging
        $logData = [
            'request_id' => $requestId,
            'url' => $context['url'],
            'method' => $context['method'],
            'total_time_ms' => $totalTime,
            'memory_mb' => $report['summary']['total_memory_mb'],
            'slow_operations' => $this->findSlowOperations($report),
            'category_breakdown' => $this->getCategoryBreakdown($report),
            'context' => $context,
        ];

        error_log('PERFORMANCE: ' . json_encode($logData));

        // Bei sehr langsamen Requests: Warnung
        if ($totalTime > $this->config['slow_threshold_ms'] * 2) {
            error_log("SLOW REQUEST WARNING: {$context['url']} took {$totalTime}ms");
        }
    }

    /**
     * Request-Kontext für Analyse sammeln
     */
    private function captureRequestContext($request): array
    {
        return [
            'url' => $request->getUri ?? $_SERVER['REQUEST_URI'] ?? 'unknown',
            'method' => $request->getMethod ?? $_SERVER['REQUEST_METHOD'] ?? 'unknown',
            'user_agent' => $request->getUserAgent ?? $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'ip' => $request->getClientIp ?? $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'content_length' => $request->getContentLength ?? $_SERVER['CONTENT_LENGTH'] ?? 0,
            'timestamp' => microtime(true),
        ];
    }

    /**
     * Langsame Operationen identifizieren
     */
    private function findSlowOperations(array $report): array
    {
        $slowOps = [];
        $threshold = 100; // ms

        foreach ($report['measurements'] as $label => $data) {
            if ($data['avg_time_ms'] > $threshold) {
                $slowOps[] = "{$label}:{$data['avg_time_ms']}ms";
            }
        }

        return $slowOps;
    }

    /**
     * Kategorie-Breakdown für Logging
     */
    private function getCategoryBreakdown(array $report): array
    {
        $breakdown = [];

        foreach ($report['categories'] as $category => $data) {
            if (isset($data['total_time_ms'])) {
                $breakdown[$category] = [
                    'time_ms' => $data['total_time_ms'],
                    'count' => $data['count'],
                    'avg_ms' => $data['avg_time_ms'],
                ];
            }
        }

        return $breakdown;
    }

    // === DUMMY-METHODEN FÜR VOLLSTÄNDIGES BEISPIEL ===

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

    private function shouldTrackAuth($request): bool
    {
        return true; // In echter Implementierung: Prüfung ob Auth nötig
    }

    private function shouldTrackAuthz($request): bool
    {
        return true; // In echter Implementierung: Prüfung ob Authz nötig
    }

    private function validateInput($request): void
    {
        // Dummy: Input-Validierung
        usleep(5000); // 5ms simulierte Verarbeitung
    }

    private function parseRequestData($request): void
    {
        // Dummy: Request-Parsing
        usleep(2000); // 2ms simulierte Verarbeitung
    }

    private function checkRateLimit($request): void
    {
        // Dummy: Rate-Limiting
        usleep(1000); // 1ms simulierte Verarbeitung
    }

    private function validateSession($request): bool
    {
        usleep(10000); // 10ms simulierte Session-Validierung
        return rand(0, 1) === 1;
    }

    private function validateToken($request): bool
    {
        usleep(5000); // 5ms simulierte Token-Validierung
        return rand(0, 1) === 1;
    }

    private function authenticateAgainstDatabase($request): bool
    {
        usleep(50000); // 50ms simulierte DB-Authentication
        return true;
    }

    private function authorizeRequest($request): bool
    {
        usleep(15000); // 15ms simulierte Authorization
        return true;
    }

    private function transformResponseContent($response): void
    {
        usleep(8000); // 8ms simulierte Content-Transformation
    }

    private function setCacheHeaders($response, $context): void
    {
        usleep(1000); // 1ms simulierte Cache-Header
    }

    private function shouldCompress($response): bool
    {
        return true;
    }

    private function compressResponse($response): void
    {
        usleep(20000); // 20ms simulierte Kompression
    }

    private function logRequestMetrics($requestId, $context, $startMemory): void
    {
        usleep(3000); // 3ms simuliertes Logging
    }

    private function isDebugMode(): bool
    {
        return $_ENV['DEBUG'] ?? false;
    }
}
