<?php declare(strict_types=1);

namespace Tracy;

use Composer\Autoload\ClassLoader;
use function count;
use const PHP_VERSION, PHP_ZTS;

/** @var DefaultBarPanel $this */

if (isset($this->cpuUsage) && $this->time) {
	foreach (getrusage() ?: [] as $key => $val) {
		$this->cpuUsage[$key] -= $val;
	}
	$userUsage = -round(($this->cpuUsage['ru_utime.tv_sec'] * 1e6 + $this->cpuUsage['ru_utime.tv_usec']) / $this->time / 10000);
	$systemUsage = -round(($this->cpuUsage['ru_stime.tv_sec'] * 1e6 + $this->cpuUsage['ru_stime.tv_usec']) / $this->time / 10000);
}

$countClasses = fn(array $list): int => count(array_filter($list, fn(string $name): bool => (new \ReflectionClass($name))->isUserDefined()));

$ipFormatter = static function (?string $ip): ?string {
	if ($ip === '127.0.0.1' || $ip === '::1') {
		$ip .= ' (localhost)';
	}
	return $ip;
};

$opcache = function_exists('opcache_get_status') ? @opcache_get_status() : null; // @ can be restricted
$cachedFiles = isset($opcache['scripts']) ? array_intersect(array_keys($opcache['scripts']), get_included_files()) : [];
$jit = $opcache['jit'] ?? null;

$info = [
	'Execution time' => number_format($this->time * 1000, 1, '.', "\u{202f}") . "\u{202f}ms",
	'CPU usage user + system' => isset($userUsage, $systemUsage) ? (int) $userUsage . "\u{202f}% + " . (int) $systemUsage . "\u{202f}%" : null,
	'Peak of allocated memory' => number_format(memory_get_peak_usage() / 1_000_000, 2, '.', "\u{202f}") . "\u{202f}MB",
	'Included files' => count(get_included_files()),
	'Classes + interfaces + traits' => $countClasses(get_declared_classes()) . ' + '
		. $countClasses(get_declared_interfaces()) . ' + ' . $countClasses(get_declared_traits()),
	'OPcache' => $opcache ? round(count($cachedFiles) * 100 / count(get_included_files())) . "\u{202f}% cached" : '–',
	'JIT' => empty($jit['buffer_size']) ? '–' : round(($jit['buffer_size'] - $jit['buffer_free']) / $jit['buffer_size'] * 100) . "\u{202f}% used",
	'Your IP' => $ipFormatter($_SERVER['REMOTE_ADDR'] ?? null),
	'Server IP' => $ipFormatter($_SERVER['SERVER_ADDR'] ?? null),
	'HTTP method / response code' => isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] . ' / ' . http_response_code() : null,
	'PHP' => PHP_VERSION . ' ' . (PHP_ZTS ? 'TS' : 'NTS'),
	'Xdebug' => extension_loaded('xdebug') ? phpversion('xdebug') . ' (' . implode(', ', xdebug_info('mode')) . ')' : null,
	'Tracy' => Debugger::Version,
	'Server' => $_SERVER['SERVER_SOFTWARE'] ?? null,
];

$info = array_map('strval', array_filter($info + (array) $this->data));

$packages = $devPackages = [];
if (class_exists(ClassLoader::class, autoload: false)) {
	$baseDir = (function () {
		$baseDir = null;
		@include dirname((string) (new \ReflectionClass(ClassLoader::class))->getFileName()) . '/autoload_psr4.php'; // @ may not exist
		return $baseDir;
	})();

	$composer = @json_decode((string) file_get_contents($baseDir . '/composer.lock')); // @ may not exist or be valid
	[$packages, $devPackages] = [(array) @$composer->packages, (array) @$composer->{'packages-dev'}]; // @ keys may not exist

	foreach ([&$packages, &$devPackages] as &$items) {
		array_walk($items, function ($package) {
			$package->hash = $package->source->reference ?? $package->dist->reference ?? null;
		}, $items);
		usort($items, fn($a, $b): int => $a->name <=> $b->name);
	}
}
