<?php

declare(strict_types=1);

namespace App\Framework\DI;

/**
 * Verwaltet alle instanziierten Objekte und Singletons
 */
final class InstanceRegistry
{
    private array $singletons = [];

    private array $instances = [];

    /**
     * @template T of object
     * @param class-string<T> $class
     * @return T|null
     */
    public function getSingleton(string $class): ?object
    {
        return $this->singletons[$class] ?? null;
    }

    /** @param class-string $class */
    public function hasSingleton(string $class): bool
    {
        return isset($this->singletons[$class]) && $this->singletons[$class] !== null;
    }

    /** @param class-string $class */
    public function setSingleton(string $class, object $instance): void
    {
        $this->singletons[$class] = $instance;
    }

    /** @param class-string $class */
    public function markAsSingleton(string $class): void
    {
        $this->singletons[$class] = null;
    }

    /** @param class-string $class */
    public function isMarkedAsSingleton(string $class): bool
    {
        return array_key_exists($class, $this->singletons);
    }

    /** @param class-string $class */
    public function getInstance(string $class): ?object
    {
        return $this->instances[$class] ?? null;
    }

    /** @param class-string $class */
    public function hasInstance(string $class): bool
    {
        return isset($this->instances[$class]);
    }

    /** @param class-string $class */
    public function setInstance(string $class, object $instance): void
    {
        $this->instances[$class] = $instance;
    }

    /** @param class-string $class */
    public function forget(string $class): void
    {
        unset($this->instances[$class], $this->singletons[$class]);
    }

    public function flush(): void
    {
        $this->instances = [];
        $this->singletons = [];
    }

    public function getAllRegistered(): array
    {
        return array_merge(
            array_keys($this->singletons),
            array_keys($this->instances)
        );
    }

    public function getSingletons(): array
    {
        return array_keys($this->singletons);
    }

    /**
     * Returns keys of currently instantiated non-singleton instances.
     * @return array<string>
     */
    public function getInstanceKeys(): array
    {
        return array_keys($this->instances);
    }
}
