<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Kernel;

use PpPhp\Core\Platform\Compatibility\CompatibilityRegistry;
use PpPhp\Core\Platform\Compatibility\CompatibilityServiceProvider;
use PpPhp\Core\Platform\Extensions\ExtensionManager;
use PpPhp\Core\Platform\Manifest\ManifestManager;
use PpPhp\Core\Platform\Modules\ModuleManager;
use PpPhp\Core\Platform\Runtime\ManifestRuntimeBootstrap;
use PpPhp\Core\Platform\Runtime\PlatformRuntimeContext;
use PpPhp\Core\Platform\Services\Registry\RegistryCollection;

final class PlatformKernel
{
    private static ?self $instance = null;

    private ?PlatformRuntimeContext $runtime = null;
    private RegistryCollection $registries;
    private CompatibilityRegistry $compatibility;
    private ?ManifestManager $manifests = null;
    private ?ModuleManager $modules = null;
    private ?ExtensionManager $plugins = null;
    private ?ExtensionManager $packages = null;
    private ?ExtensionManager $themes = null;
    private string $basePath = '';

    private function __construct()
    {
        $this->registries = new RegistryCollection();
        $this->compatibility = (new CompatibilityServiceProvider())->register($this->registries);
    }

    public static function instance(): self
    {
        if (!self::$instance instanceof self) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public static function reset(): void
    {
        self::$instance = null;
    }

    public function boot(string $basePath): self
    {
        $this->basePath = $basePath;

        $this->manifests = new ManifestManager($basePath);
        $this->manifests->load();

        $this->modules = new ModuleManager($this->manifests);
        $this->modules->load();

        $this->plugins = new ExtensionManager($this->manifests, 'plugin');
        $this->packages = new ExtensionManager($this->manifests, 'package');
        $this->themes = new ExtensionManager($this->manifests, 'theme');

        if (class_exists(ManifestRuntimeBootstrap::class)) {
            $this->runtime = (new ManifestRuntimeBootstrap())->boot($basePath);
            $this->registries = $this->runtime->registries();
        }

        $this->compatibility = (new CompatibilityServiceProvider())->register($this->registries);

        return $this;
    }

    public function basePath(): string { return $this->basePath; }
    public function runtime(): ?PlatformRuntimeContext { return $this->runtime; }
    public function registries(): RegistryCollection { return $this->registries; }
    public function compatibility(): CompatibilityRegistry { return $this->compatibility; }

    public function manifests(): ManifestManager
    {
        if (!$this->manifests instanceof ManifestManager) {
            $this->manifests = new ManifestManager($this->basePath !== '' ? $this->basePath : dirname(__DIR__, 4));
            $this->manifests->load();
        }

        return $this->manifests;
    }

    public function modules(): ModuleManager
    {
        if (!$this->modules instanceof ModuleManager) {
            $this->modules = new ModuleManager($this->manifests());
            $this->modules->load();
        }

        return $this->modules;
    }

    public function plugins(): ExtensionManager
    {
        if (!$this->plugins instanceof ExtensionManager) {
            $this->plugins = new ExtensionManager($this->manifests(), 'plugin');
        }

        return $this->plugins;
    }

    public function packages(): ExtensionManager
    {
        if (!$this->packages instanceof ExtensionManager) {
            $this->packages = new ExtensionManager($this->manifests(), 'package');
        }

        return $this->packages;
    }

    public function themes(): ExtensionManager
    {
        if (!$this->themes instanceof ExtensionManager) {
            $this->themes = new ExtensionManager($this->manifests(), 'theme');
        }

        return $this->themes;
    }

    public function toArray(): array
    {
        return [
            'basePath' => $this->basePath,
            'runtimeBooted' => $this->runtime instanceof PlatformRuntimeContext,
            'manifestCount' => $this->manifests()->collection()->count(),
            'moduleCount' => $this->modules()->count(),
            'pluginCount' => $this->plugins()->count(),
            'packageCount' => $this->packages()->count(),
            'themeCount' => $this->themes()->count(),
            'registries' => $this->registries->toArray(),
            'compatibility' => $this->compatibility->toArray(),
        ];
    }
}
