<?php

namespace App\Framework\DI;

use App\Framework\DI\Exceptions\LazyLoadingException;
use App\Framework\Reflection\ReflectionProvider;
use Closure;

/**
 * Behandelt Lazy Loading von Objekten
 */
final class LazyInstantiator
{
    private array $factories = [];

    public function __construct(
        private readonly ReflectionProvider $reflectionProvider,
        private readonly Closure $instanceCreator
    ) {}

    public function canUseLazyLoading(string $class, InstanceRegistry $registry): bool
    {
        return !$registry->hasSingleton($class);
    }

    public function createLazyInstance(string $class): object
    {
        $reflection = $this->reflectionProvider->getClass($class);

        if (!isset($this->factories[$class])) {
            $this->factories[$class] = fn() => ($this->instanceCreator)($class);
        }

        $factory = $this->factories[$class];

        if (method_exists($reflection, 'getLazyGhost')) {
            return $reflection->getLazyGhost($factory);
        }

        if (method_exists($reflection, 'getLazyProxy')) {
            return $reflection->getLazyProxy($factory);
        }

        throw new LazyLoadingException("Lazy loading not supported for class: {$class}");
    }

    public function forgetFactory(string $class): void
    {
        unset($this->factories[$class]);
    }

    public function flushFactories(): void
    {
        $this->factories = [];
    }
}
