<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Compiler;

use PpPhp\Core\Platform\DI\Definition\ClassDefinition;
use PpPhp\Core\Platform\DI\Definition\FactoryDefinition;
use PpPhp\Core\Platform\DI\Definition\InstanceDefinition;
use PpPhp\Core\Platform\DI\Definition\AliasDefinition;
use PpPhp\Core\Platform\DI\Definition\ValueDefinition;
use PpPhp\Core\Platform\DI\Contracts\DefinitionInterface;

final class DefinitionCompiler
{
    public function compile(DefinitionInterface $definition): CompiledDefinition
    {
        $payload = [];

        if ($definition instanceof ClassDefinition) {
            $payload['className'] = $definition->className();
        } elseif ($definition instanceof FactoryDefinition) {
            $payload['factory'] = 'Closure';
        } elseif ($definition instanceof InstanceDefinition) {
            $payload['instanceClass'] = $definition->instance()::class;
        } elseif ($definition instanceof AliasDefinition) {
            $payload['target'] = $definition->target();
        } elseif ($definition instanceof ValueDefinition) {
            $payload['valueType'] = gettype($definition->value());
            $payload['value'] = $this->exportableValue($definition->value());
        }

        return new CompiledDefinition(
            $definition->id(),
            $definition->type(),
            $definition->lifetime(),
            $payload,
            $definition->tags(),
            $definition->aliases(),
            $definition->metadata()
        );
    }

    private function exportableValue(mixed $value): mixed
    {
        if (is_scalar($value) || $value === null || is_array($value)) {
            return $value;
        }

        return '[non-exportable:' . gettype($value) . ']';
    }
}
