<?php

namespace App\Application\Admin;

use App\Framework\Attributes\Route;
use App\Framework\Auth\Auth;
use App\Framework\Config\TypedConfiguration;
use App\Framework\Core\VersionInfo;
use App\Framework\DI\DefaultContainer;
use App\Framework\Http\HttpResponse;
use App\Framework\Http\Method;
use App\Framework\Http\Response;
use App\Framework\Meta\MetaData;
use App\Framework\Meta\OpenGraphTypeWebsite;
use App\Framework\Performance\MemoryUsageTracker;
use App\Framework\Router\Result\ViewResult;
use App\Framework\Http\Session\SessionManager;
use App\Framework\Http\Status;
use Dom\HTMLDocument;

final readonly class Dashboard
{
    public function __construct(
        private DefaultContainer   $container,
        private VersionInfo        $versionInfo,
        private MemoryUsageTracker $memoryTracker,
        private TypedConfiguration $config,
    ) {}

    #[Auth]
    #[Route(path: '/admin', method: Method::GET)]
    public function show(): ViewResult
    {
        $stats = [
            'frameworkVersion' => $this->versionInfo->getVersion(),
            'phpVersion' => PHP_VERSION,
            'memoryUsage' => $this->formatBytes(memory_get_usage(true)),
            'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
            'serverInfo' => $_SERVER['SERVER_SOFTWARE'] ?? 'Unknown',
            'serverTime' => date('Y-m-d H:i:s'),
            'timezone' => date_default_timezone_get(),
            'operatingSystem' => PHP_OS,
            'loadedExtensions' => $this->getLoadedExtensions(),
            'sessionCount' => $this->getActiveSessionCount(),
            'uptime' => $this->getServerUptime(),
            'servicesCount' => 4,#count($this->container->getServiceIds()),
        ];

        #debug($stats);

        return new ViewResult(
            template: 'dashboard',
            metaData: new MetaData('Admin Dashboard'),
            data: [
                'title' => 'Admin Dashboard',
                'stats' => $stats
            ]
        );
    }

    #[Auth]
    #[Route(path: '/admin/routes', method: Method::GET)]
    public function routes(): ViewResult
    {
        $routeRegistry = $this->container->get('App\Framework\Router\RouteRegistry');
        $routes = $routeRegistry->getRoutes();

        // Sort routes by path for better readability
        usort($routes, function($a, $b) {
            return strcmp($a->path, $b->path);
        });

        return new ViewResult(
            template: 'admin/routes',
            metaData: new MetaData('', ''),
            data: [
                'title' => 'Routen-Übersicht',
                'routes' => $routes
            ]
        );
    }

    #[Auth]
    #[Route(path: '/admin/services', method: Method::GET)]
    public function services(): ViewResult
    {
        $services = $this->container->getServiceIds();
        sort($services);

        return new ViewResult(
            template: 'admin/services',
            data: [
                'title' => 'Registrierte Dienste',
                'services' => $services
            ]
        );
    }

    #[Auth]
    #[Route(path: '/admin/environment', method: Method::GET)]
    public function environment(): ViewResult
    {
        $env = [];
        foreach ($_ENV as $key => $value) {
            // Maskiere sensible Daten
            if (str_contains(strtolower($key), 'password') ||
                str_contains(strtolower($key), 'secret') ||
                str_contains(strtolower($key), 'key')) {
                $value = '********';
            }
            $env[$key] = $value;
        }

        ksort($env);

        dd($env);

        return new ViewResult(
            template: 'admin/environment',
            metaData: new MetaData('', ''),
            data: [
                'title' => 'Umgebungsvariablen',
                'env' => $env
            ]
        );
    }

    #[Auth]
    #[Route('/admin/phpinfo')]
    #[Route(path: '/admin/phpinfo/{mode}', method: Method::GET)]
    public function phpInfo(int $mode = 1): Response
    {
        ob_start();
        phpinfo($mode);
        $phpinfo = ob_get_clean();

        // Extraktion des <body> Inhalts, um nur den relevanten Teil anzuzeigen
        preg_match('/<body[^>]*>(.*?)<\/body>/si', $phpinfo, $matches);
        $body = $matches[1] ?? $phpinfo;

        // Entfernen der Navigation-Links am Anfang
        #$body = preg_replace('/<div class="center">(.*?)<\/div>/si', '', $body, 1);

        #debug($body);

        // Hinzufügen von eigenen Styles
        $customStyles = '<style>
            .phpinfo { font-family: system-ui, sans-serif; line-height: 1.5; }
            .phpinfo table { border-collapse: collapse; width: 100%; margin-bottom: 1rem; }
            .phpinfo td, .phpinfo th { padding: 0.5rem; border: 1px solid #ddd; }
            .phpinfo h1, .phpinfo h2 { margin-bottom: 1rem; }
            .phpinfo hr { margin: 2rem 0; }
        </style>';

        $responseBody = '<!DOCTYPE html>
        <html lang="de">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>PHP Info</title>
            <link rel="stylesheet" href="/css/admin.css">
            ' . $customStyles . '
        </head>
        <body class="admin-page">
            <div class="admin-header">
                <h1>PHP Info</h1>
                <a href="/admin" class="btn">Zurück zum Dashboard</a>
            </div>
            <div class="admin-content">
                <div class="phpinfo">' . $body . '</div>
            </div>
        </body>
        </html>';

        echo $responseBody;
        die();

        return new HttpResponse(status: Status::OK, body: $responseBody);
    }

    #[Auth]
    #[Route(path: '/admin/performance', method: Method::GET)]
    public function performance(): ViewResult
    {
        $performanceData = [
            'currentMemoryUsage' => $this->formatBytes(memory_get_usage(true)),
            'peakMemoryUsage' => $this->formatBytes(memory_get_peak_usage(true)),
            'memoryLimit' => $this->formatBytes($this->getMemoryLimitInBytes()),
            'memoryUsagePercentage' => round((memory_get_usage(true) / $this->getMemoryLimitInBytes()) * 100, 2),
            'loadAverage' => function_exists('sys_getloadavg') ? sys_getloadavg() : ['N/A', 'N/A', 'N/A'],
            'opcacheEnabled' => function_exists('opcache_get_status') ? 'Ja' : 'Nein',
            'executionTime' => number_format(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 4) . ' Sekunden',
            'includedFiles' => count(get_included_files()),
        ];

        if (function_exists('opcache_get_status')) {
            try {
                $opcacheStatus = opcache_get_status(false);
                if ($opcacheStatus !== false) {
                    $performanceData['opcacheMemoryUsage'] = $this->formatBytes($opcacheStatus['memory_usage']['used_memory']);
                    $performanceData['opcacheCacheHits'] = number_format($opcacheStatus['opcache_statistics']['hits']);
                    $performanceData['opcacheMissRate'] = number_format($opcacheStatus['opcache_statistics']['misses'] /
                        ($opcacheStatus['opcache_statistics']['hits'] + $opcacheStatus['opcache_statistics']['misses']) * 100, 2) . '%';
                }
            } catch (\Throwable $e) {
                // OPCache Status konnte nicht abgerufen werden
                $performanceData['opcacheError'] = $e->getMessage();
            }
        }

        return new ViewResult(
            template: 'performance',
            data: [
                'title' => 'Performance-Daten',
                'performance' => $performanceData
            ]
        );
    }

    #[Auth]
    #[Route(path: '/admin/redis', method: Method::GET)]
    public function redisInfo(): ViewResult
    {
        $redisInfo = [];

        try {
            $redis = $this->container->get('Predis\Client');
            $info = $redis->info();
            $redisInfo['status'] = 'Verbunden';
            $redisInfo['version'] = $info['redis_version'];
            $redisInfo['uptime'] = $this->formatUptime((int)$info['uptime_in_seconds']);
            $redisInfo['memory'] = $this->formatBytes((int)$info['used_memory']);
            $redisInfo['peak_memory'] = $this->formatBytes((int)$info['used_memory_peak']);
            $redisInfo['clients'] = $info['connected_clients'];
            $redisInfo['keys'] = $redis->dbsize();

            // Einige Schlüssel auflisten (begrenzt auf 50)
            $keys = $redis->keys('*');
            $redisInfo['key_sample'] = array_slice($keys, 0, 50);
        } catch (\Throwable $e) {
            $redisInfo['status'] = 'Fehler: ' . $e->getMessage();
        }

        return new ViewResult(
            template: 'admin/redis',
            data: [
                'title' => 'Redis Information',
                'redis' => $redisInfo
            ]
        );
    }

    private function formatBytes(int $bytes, int $precision = 2): string
    {
        $units = ['B', 'KB', 'MB', 'GB', 'TB'];

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= (1 << (10 * $pow));

        return round($bytes, $precision) . ' ' . $units[$pow];
    }

    private function getMemoryLimitInBytes(): int
    {
        $memoryLimit = ini_get('memory_limit');

        if ($memoryLimit === '-1') {
            return PHP_INT_MAX;
        }

        $value = (int) $memoryLimit;
        $unit = strtolower($memoryLimit[strlen($memoryLimit)-1]);

        switch($unit) {
            case 'g':
                $value *= 1024;
            case 'm':
                $value *= 1024;
            case 'k':
                $value *= 1024;
                break;
        }

        return $value;
    }

    private function getLoadedExtensions(): array
    {
        $extensions = get_loaded_extensions();
        sort($extensions);
        return $extensions;
    }

    private function getActiveSessionCount(): int
    {
        try {
            if ($this->container->has(SessionManager::class)) {
                $sessionManager = $this->container->get(SessionManager::class);
                // Diese Methode müsste implementiert werden
                return $sessionManager->getActiveSessionCount();
            }
        } catch (\Throwable $e) {
            // Silent fail
        }

        return 0;
    }

    private function getServerUptime(): string
    {
        // Für Linux-Systeme
        if (function_exists('shell_exec') && stripos(PHP_OS, 'Linux') !== false) {
            $uptime = shell_exec('uptime -p');
            if ($uptime) {
                return $uptime;
            }
        }

        // Fallback
        return 'Nicht verfügbar';
    }

    private function formatUptime(int $seconds): string
    {
        $days = floor($seconds / 86400);
        $hours = floor(($seconds % 86400) / 3600);
        $minutes = floor(($seconds % 3600) / 60);
        $remainingSeconds = $seconds % 60;

        $result = '';
        if ($days > 0) {
            $result .= "$days Tage, ";
        }

        return $result . sprintf('%02d:%02d:%02d', $hours, $minutes, $remainingSeconds);
    }
}
