<?php

declare(strict_types=1);

namespace App\Framework\Console\Health\Checks;

use App\Framework\Console\Health\HealthCheck;
use App\Framework\Console\Health\HealthCheckResult;
use App\Framework\Core\ValueObjects\Bytes;

final readonly class PerformanceHealthCheck implements HealthCheck
{
    public function getName(): string
    {
        return 'System Performance';
    }

    public function getDescription(): string
    {
        return 'Checks system performance metrics and resource availability';
    }

    public function check(): HealthCheckResult
    {
        $details = [];
        $warnings = [];

        // Memory usage check
        $memoryUsage = Bytes::fromBytes(memory_get_usage(true));
        $memoryLimit = $this->parseMemoryLimit(ini_get('memory_limit'));
        $memoryPercentage = $memoryLimit->getBytes() > 0 ?
            ($memoryUsage->getBytes() / $memoryLimit->getBytes()) * 100 : 0;

        $details['memory_usage'] = $memoryUsage->toHuman();
        $details['memory_limit'] = $memoryLimit->toHuman();
        $details['memory_percentage'] = round($memoryPercentage, 2);

        if ($memoryPercentage > 80) {
            $warnings[] = "High memory usage: {$details['memory_percentage']}%";
        }

        // Execution time limit check
        $timeLimit = ini_get('max_execution_time');
        $details['max_execution_time'] = $timeLimit === '0' ? 'unlimited' : $timeLimit . 's';

        if ($timeLimit !== '0' && (int) $timeLimit < 300) {
            $warnings[] = "Low execution time limit: {$timeLimit}s";
        }

        // Disk space check (if possible)
        $diskSpace = disk_free_space('.');
        if ($diskSpace !== false) {
            $totalSpace = disk_total_space('.');
            $diskPercentage = $totalSpace > 0 ? (($totalSpace - $diskSpace) / $totalSpace) * 100 : 0;

            $details['disk_free'] = Bytes::fromBytes($diskSpace)->toHuman();
            $details['disk_usage_percentage'] = round($diskPercentage, 2);

            if ($diskPercentage > 90) {
                $warnings[] = "Low disk space: {$details['disk_usage_percentage']}% used";
            }
        }

        // PHP version check
        $phpVersion = PHP_VERSION;
        $details['php_version'] = $phpVersion;

        if (version_compare($phpVersion, '8.1', '<')) {
            $warnings[] = "Outdated PHP version: {$phpVersion}";
        }

        // Extension checks
        $requiredExtensions = ['pdo', 'json', 'mbstring'];
        $missingExtensions = [];

        foreach ($requiredExtensions as $extension) {
            if (! extension_loaded($extension)) {
                $missingExtensions[] = $extension;
            }
        }

        if (! empty($missingExtensions)) {
            $warnings[] = "Missing PHP extensions: " . implode(', ', $missingExtensions);
        }

        $details['loaded_extensions'] = array_intersect($requiredExtensions, get_loaded_extensions());

        if (! empty($warnings)) {
            return HealthCheckResult::warning(
                'Performance issues detected: ' . implode('; ', $warnings),
                $details,
                'Consider increasing resource limits or updating system configuration'
            );
        }

        return HealthCheckResult::healthy(
            'System performance is good',
            $details
        );
    }

    public function isRequired(): bool
    {
        return true;
    }

    private function parseMemoryLimit(string $limit): Bytes
    {
        if ($limit === '-1') {
            return Bytes::fromBytes(0); // Unlimited
        }

        $limit = strtolower(trim($limit));
        $multiplier = 1;

        if (str_ends_with($limit, 'g')) {
            $multiplier = 1024 * 1024 * 1024;
            $limit = substr($limit, 0, -1);
        } elseif (str_ends_with($limit, 'm')) {
            $multiplier = 1024 * 1024;
            $limit = substr($limit, 0, -1);
        } elseif (str_ends_with($limit, 'k')) {
            $multiplier = 1024;
            $limit = substr($limit, 0, -1);
        }

        return Bytes::fromBytes((int) $limit * $multiplier);
    }
}
