<?php

declare(strict_types=1);

namespace PpPhp\Core\Platform\Runtime;

use PpPhp\Core\Platform\Services\Blueprint\BlueprintCollection;
use PpPhp\Core\Platform\Services\Blueprint\BlueprintFactory;
use PpPhp\Core\Platform\Services\Container\PlatformServiceHub;
use PpPhp\Core\Platform\Services\Container\ServiceContainer;
use PpPhp\Core\Platform\Services\Definition\ServiceDefinition;
use PpPhp\Core\Platform\Services\Descriptor\DescriptorCollection;
use PpPhp\Core\Platform\Services\Descriptor\DescriptorFactory;
use PpPhp\Core\Platform\Services\Metadata\MetadataFactory;
use PpPhp\Core\Platform\Services\Registry\RegistryCollection;

final class PlatformRuntimeBootstrap
{
    public function boot(string $basePath, array $serviceDeclarations = []): PlatformRuntimeContext
    {
        $configuration = new RuntimeConfiguration($basePath, (bool)($serviceDeclarations['_debug'] ?? false));
        $environment = new RuntimeEnvironment((string)($serviceDeclarations['_environment'] ?? 'local'));
        $state = new RuntimeState();

        $descriptors = new DescriptorCollection();
        $blueprints = new BlueprintCollection();
        $registries = new RegistryCollection();

        foreach ($serviceDeclarations as $key => $declaration) {
            if (str_starts_with((string)$key, '_') || !is_array($declaration)) {
                continue;
            }

            $descriptor = DescriptorFactory::service($declaration, 'runtime-bootstrap');
            $descriptors->add($descriptor);

            $blueprint = BlueprintFactory::fromDescriptor($descriptor);
            $blueprints->add($blueprint);

            $metadata = MetadataFactory::service($descriptor->toArray());
            $definition = ServiceDefinition::metadataOnly($metadata);
            $registries->services->register($definition);

            foreach ($metadata->aliases() as $alias) {
                $registries->aliases->register($alias->alias(), $alias->target());
            }

            foreach ($metadata->capabilities() as $capability) {
                $registries->capabilities->register($metadata->id(), $capability);
            }
        }

        $container = new ServiceContainer($registries->services, $registries->aliases);
        $hub = new PlatformServiceHub($registries, $container);

        $state->markBooted();
        $state->message('Platform runtime booted.');

        return new PlatformRuntimeContext(
            $configuration,
            $environment,
            $state,
            $descriptors,
            $blueprints,
            $registries,
            $hub
        );
    }
}
