<?php

declare(strict_types=1);

namespace App\Application\Admin;

use App\Framework\Attributes\Route;
use App\Framework\Auth\Auth;
use App\Framework\Core\VersionInfo;
use App\Framework\DateTime\Clock;
use App\Framework\Http\Method;
use App\Framework\Meta\MetaData;
use App\Framework\Performance\MemoryMonitor;
use App\Framework\Process\Services\SystemInfoService;
use App\Framework\Router\AdminRoutes;
use App\Framework\Router\Result\ViewResult;

final readonly class Dashboard
{
    public function __construct(
        private VersionInfo $versionInfo,
        private MemoryMonitor $memoryMonitor,
        private Clock $clock,
        private SystemInfoService $systemInfo,
    ) {
    }

    #[Auth]
    #[Route(path: '/admin', method: Method::GET, name: AdminRoutes::DASHBOARD)]
    public function show(): ViewResult
    {
        $sysInfo = ($this->systemInfo)();

        return new ViewResult(
            template: 'dashboard',
            metaData: new MetaData('Admin Dashboard', 'Administrative control panel'),
            data: [
                'title' => 'Admin Dashboard',
                'page_title' => 'Admin Dashboard',
                'current_path' => '/admin',
                'framework_version' => $this->versionInfo->getVersion(),
                'uptime_formatted' => $this->formatUptime($sysInfo->uptime),
                'boot_time' => $sysInfo->uptime->bootTime->format('Y-m-d H:i:s'),
                'memory_usage_formatted' => $this->memoryMonitor->getCurrentMemory()->toHumanReadable(),
                'peak_memory_formatted' => $this->memoryMonitor->getPeakMemory()->toHumanReadable(),
                'load_average' => $this->formatLoadAverage($sysInfo->load),
                'system_memory_total' => $this->formatBytes($sysInfo->memory->totalBytes),
                'system_memory_used' => $this->formatBytes($sysInfo->memory->usedBytes),
                'system_memory_free' => $this->formatBytes($sysInfo->memory->freeBytes),
                'system_memory_percent' => round(($sysInfo->memory->usedBytes / $sysInfo->memory->totalBytes) * 100, 1),
                'cpu_cores' => $sysInfo->cpu->cores,
                'cpu_model' => $sysInfo->cpu->model,
                'disk_total' => $this->formatBytes($sysInfo->disk->totalBytes),
                'disk_used' => $this->formatBytes($sysInfo->disk->usedBytes),
                'disk_free' => $this->formatBytes($sysInfo->disk->availableBytes),
                'disk_percent' => round(($sysInfo->disk->usedBytes / $sysInfo->disk->totalBytes) * 100, 1),
                'processes_total' => $sysInfo->processes->total,
                'processes_running' => $sysInfo->processes->running,
                'processes_sleeping' => $sysInfo->processes->sleeping,
                'db_pool_size' => 10,
                'db_active_connections' => 3,
                'cache_hit_rate' => '85%',
                'cache_total_operations' => number_format(12547),
                'requests_today' => number_format(1247),
                'errors_today' => 3,
                'last_deployment' => $this->clock->now()->format('Y-m-d H:i'),
                'clear_cache_url' => '/admin/infrastructure/cache/reset',
                'logs_url' => '/admin/infrastructure/logs',
                'migrations_url' => '/admin/infrastructure/migrations',
            ]
        );
    }

    private function formatLoadAverage(\App\Framework\Process\ValueObjects\SystemInfo\LoadAverage $load): string
    {
        return sprintf('%.2f, %.2f, %.2f', $load->oneMinute, $load->fiveMinutes, $load->fifteenMinutes);
    }

    private function formatUptime(\App\Framework\Process\ValueObjects\SystemInfo\SystemUptime $uptime): string
    {
        $duration = $uptime->uptime;

        $totalHours = (int) floor($duration->toHours());
        $totalMinutes = (int) floor($duration->toMinutes());

        $days = (int) floor($totalHours / 24);
        $hours = $totalHours % 24;
        $minutes = $totalMinutes % 60;

        $parts = [];
        if ($days > 0) {
            $parts[] = $days . ' ' . ($days === 1 ? 'Tag' : 'Tage');
        }
        if ($hours > 0) {
            $parts[] = $hours . ' ' . ($hours === 1 ? 'Stunde' : 'Stunden');
        }
        if ($minutes > 0 && $days === 0) {
            $parts[] = $minutes . ' ' . ($minutes === 1 ? 'Minute' : 'Minuten');
        }

        return !empty($parts) ? implode(', ', $parts) : 'Weniger als eine Minute';
    }

    private function formatBytes(int $bytes): 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 /= (1024 ** $pow);

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