<?php

declare(strict_types=1);

namespace App\Framework\Database;

use App\Framework\Database\Driver\DriverConfig;
use App\Framework\Database\Exception\DatabaseException;
use ReflectionClass;

final readonly class LazyConnectionFactory
{
    public static function createLazyGhost(
        array|DriverConfig $config,
        string $connectionClass = PdoConnection::class
    ): ConnectionInterface {
        $reflection = new ReflectionClass($connectionClass);

        // Stelle sicher, dass die Klasse ConnectionInterface implementiert
        if (! $reflection->implementsInterface(ConnectionInterface::class)) {
            throw new DatabaseException(
                "Class {$connectionClass} must implement ConnectionInterface"
            );
        }

        // Erstelle LazyGhost mit Initializer
        $ghost = $reflection->newLazyGhost(
            initializer: function (object $object) use ($config, $connectionClass): void {
                self::initializeLazyConnection($object, $config, $connectionClass);
            }
        );

        return $ghost;
    }

    private static function initializeLazyConnection(
        object $ghost,
        array|DriverConfig $config,
        string $connectionClass
    ): void {
        // Erstelle die echte Verbindung
        $realConnection = DatabaseFactory::createDirectConnection($config);

        // Kopiere alle Properties von der echten Verbindung in das Ghost
        $ghostReflection = new ReflectionClass($ghost);
        $realReflection = new ReflectionClass($realConnection);

        // Für PdoConnection: kopiere die PDO-Instanz
        if ($realConnection instanceof PdoConnection) {
            $pdoProperty = $realReflection->getProperty('pdo');
            $ghostPdoProperty = $ghostReflection->getProperty('pdo');

            $ghostPdoProperty->setValue($ghost, $pdoProperty->getValue($realConnection));
        }

        // Zusätzliche Properties falls vorhanden
        foreach ($realReflection->getProperties() as $property) {
            if ($ghostReflection->hasProperty($property->getName())) {
                $ghostProperty = $ghostReflection->getProperty($property->getName());
                $ghostProperty->setValue($ghost, $property->getValue($realConnection));
            }
        }
    }

    public static function isLazyGhost(object $object): bool
    {
        $reflection = new ReflectionClass($object);

        return $reflection->isUninitializedLazyObject($object);
    }

    public static function initializeLazyGhost(object $object): void
    {
        $reflection = new ReflectionClass($object);
        if ($reflection->isUninitializedLazyObject($object)) {
            $reflection->initializeLazyObject($object);
        }
    }

    public static function resetLazyGhost(object $object): void
    {
        $reflection = new ReflectionClass($object);
        if (! $reflection->isUninitializedLazyObject($object)) {
            $reflection->resetAsLazyGhost($object, function (object $obj) use ($object): void {
                // Re-initialize with same logic as original
                // This would require storing the original config somewhere
                throw new DatabaseException('LazyGhost reset requires stored configuration');
            });
        }
    }
}
