<?php
declare(strict_types=1);

namespace App\Kernel;

use App\Core\Database;
use Throwable;

final class KernelRegistry
{
    public function snapshot(): array
    {
        $manifests = $this->discoverManifests();
        return [
            'manifests' => $manifests,
            'engines' => $this->rows('axiom_engines'),
            'modules' => $this->rows('axiom_modules'),
            'services' => $this->rows('axiom_services'),
            'events' => $this->rows('axiom_events', 'id DESC', 50),
            'dependencies' => $this->rows('axiom_dependencies'),
            'checks' => $this->compatibilityChecks($manifests),
        ];
    }

    public function discoverManifests(): array
    {
        $directory = BASE_PATH . '/app/Kernel/Manifests';
        if (!is_dir($directory)) {
            return [];
        }

        $result = [];
        foreach (glob($directory . '/*.json') ?: [] as $file) {
            $raw = file_get_contents($file);
            $manifest = $raw === false ? null : json_decode($raw, true);
            if (!is_array($manifest)) {
                $result[] = [
                    'code' => basename($file, '.json'),
                    'name' => basename($file),
                    'status' => 'invalid',
                    'error' => 'JSON invalide',
                ];
                continue;
            }
            $manifest['source'] = basename($file);
            $manifest['status'] = $this->manifestValid($manifest) ? 'ok' : 'invalid';
            $result[] = $manifest;
        }

        usort($result, static fn(array $a, array $b): int => strcmp((string)($a['name'] ?? ''), (string)($b['name'] ?? '')));
        return $result;
    }

    private function manifestValid(array $manifest): bool
    {
        foreach (['code', 'name', 'version', 'type'] as $required) {
            if (!isset($manifest[$required]) || trim((string)$manifest[$required]) === '') {
                return false;
            }
        }
        return true;
    }

    private function compatibilityChecks(array $manifests): array
    {
        $installed = is_file(BASE_PATH . '/VERSION') ? trim((string)file_get_contents(BASE_PATH . '/VERSION')) : '0.0.0';
        $checks = [];
        foreach ($manifests as $manifest) {
            $status = ($manifest['status'] ?? '') === 'ok';
            $message = $status ? 'Manifeste conforme.' : 'Manifeste incomplet ou invalide.';
            $minimum = (string)($manifest['requires']['platform'] ?? '0.0.0');
            if ($status && version_compare($installed, $minimum, '<')) {
                $status = false;
                $message = 'Version AXIOM minimale requise : ' . $minimum;
            }
            $checks[] = [
                'code' => (string)($manifest['code'] ?? 'inconnu'),
                'name' => (string)($manifest['name'] ?? 'Composant inconnu'),
                'status' => $status ? 'ok' : 'warning',
                'message' => $message,
            ];
        }
        return $checks;
    }

    private function rows(string $table, string $order = 'code ASC', int $limit = 250): array
    {
        if (!preg_match('/^[a-z0-9_]+$/i', $table) || !preg_match('/^[a-z0-9_ ,]+$/i', $order)) {
            return [];
        }
        try {
            $sql = sprintf('SELECT * FROM `%s` ORDER BY %s LIMIT %d', $table, $order, max(1, min($limit, 500)));
            return Database::connection()->query($sql)->fetchAll() ?: [];
        } catch (Throwable) {
            return [];
        }
    }
}
