<?php
declare(strict_types=1);
namespace App\Runtime;
use App\Core\Modules\ModuleManager;
use App\Core\Router;
use App\Foundation\Application;
use RuntimeException;
use Throwable;

final class ModuleRuntime
{
    private array $modules = [];
    private array $instances = [];
    private array $errors = [];
    private string $stateFile;

    public function __construct(private readonly Application $app, private readonly array $paths)
    {
        $this->stateFile = rtrim((string)$app->container()->get('base_path'), '/\\') . '/storage/runtime/modules.json';
    }

    public function discoverAndBoot(): void
    {
        $manager = new ModuleManager($this->paths);
        $state = $this->readState();
        foreach ($manager->discover() as $code => $manifest) {
            $manifest['enabled'] = array_key_exists($code, $state) ? (bool)$state[$code] : (bool)($manifest['enabled'] ?? true);
            $manifest['runtime_status'] = $manifest['enabled'] ? 'discovered' : 'disabled';
            $this->modules[$code] = $manifest;
            if (!$manifest['enabled'] || ($manifest['status'] ?? '') !== 'ok') continue;
            try {
                $class = (string)($manifest['entry'] ?? '');
                if ($class === '' || !class_exists($class)) throw new RuntimeException('Classe d’entrée introuvable : ' . $class);
                $instance = $this->app->container()->get($class);
                if (!$instance instanceof ModuleInterface) throw new RuntimeException($class . ' doit implémenter ModuleInterface.');
                $instance->boot($this->app);
                $this->instances[$code] = $instance;
                $this->modules[$code]['runtime_status'] = 'booted';
                $this->app->modules()->register($code, $this->modules[$code]);
                $this->app->events()->dispatch('axiom.module.booted', ['code'=>$code,'manifest'=>$manifest]);
            } catch (Throwable $e) {
                $this->modules[$code]['runtime_status'] = 'error';
                $this->modules[$code]['runtime_error'] = $e->getMessage();
                $this->errors[$code] = $e->getMessage();
            }
        }
    }

    public function registerRoutes(Router $router): void
    {
        foreach ($this->instances as $code => $instance) {
            try { $instance->routes($router); }
            catch (Throwable $e) { $this->errors[$code] = $e->getMessage(); $this->modules[$code]['runtime_status']='error'; }
        }
    }

    public function setEnabled(string $code, bool $enabled): void
    {
        if (!isset($this->modules[$code])) throw new RuntimeException('Module inconnu : ' . $code);
        $state = $this->readState(); $state[$code] = $enabled;
        $dir = dirname($this->stateFile);
        if (!is_dir($dir) && !mkdir($dir, 0775, true) && !is_dir($dir)) throw new RuntimeException('Impossible de créer le registre Runtime.');
        if (file_put_contents($this->stateFile, json_encode($state, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOCK_EX) === false) throw new RuntimeException('Impossible d’enregistrer l’état du module.');
    }

    public function snapshot(): array { return ['modules'=>$this->modules,'errors'=>$this->errors,'booted'=>array_keys($this->instances),'state_file'=>$this->stateFile]; }
    private function readState(): array
    {
        if (!is_file($this->stateFile)) return [];
        $data=json_decode((string)file_get_contents($this->stateFile), true);
        return is_array($data) ? $data : [];
    }
}
