<?php

declare(strict_types=1);

namespace App\Framework\Database\Services;

use App\Framework\Database\DatabaseManager;
use App\Framework\Database\Events\EntityEventManager;
use App\Framework\Database\IdentityMap;
use App\Framework\Database\IdGenerator;
use App\Framework\Database\Metadata\MetadataRegistry;

final readonly class EntityUtilities
{
    public function __construct(
        private DatabaseManager $databaseManager,
        private MetadataRegistry $metadataRegistry,
        private IdentityMap $identityMap,
        private EntityEventManager $entityEventManager
    ) {
    }

    /**
     * Detach entity from identity map
     */
    public function detach(object $entity): void
    {
        $metadata = $this->metadataRegistry->getMetadata($entity::class);

        // ID der Entity ermitteln
        $constructor = $metadata->reflection->getConstructor();
        if ($constructor) {
            foreach ($constructor->getParameters() as $param) {
                $paramName = $param->getName();
                $propertyMetadata = $metadata->getProperty($paramName);

                if ($propertyMetadata && $propertyMetadata->columnName === $metadata->idColumn) {
                    try {
                        $property = $metadata->reflection->getProperty($paramName);
                        $id = $property->getValue($entity);

                        // Entity Detached Event dispatchen (vor Identity Map Remove)
                        $this->entityEventManager->entityDetached($entity, $entity::class, $id);

                        $this->identityMap->remove($entity::class, $id);

                        break;
                    } catch (\ReflectionException) {
                        // Property nicht gefunden
                    }
                }
            }
        }
    }

    /**
     * Clear identity map
     */
    public function clear(): void
    {
        $this->identityMap->clear();
    }

    /**
     * Get identity map statistics
     */
    public function getIdentityMapStats(): array
    {
        return $this->identityMap->getStats();
    }

    /**
     * Get entity metadata
     */
    public function getMetadata(string $entityClass): \App\Framework\Database\Metadata\EntityMetadata
    {
        return $this->metadataRegistry->getMetadata($entityClass);
    }

    /**
     * Generiert eine einzigartige ID für Entities
     */
    public function generateId(): string
    {
        return IdGenerator::generate();
    }

    /**
     * Get the identity map (for QueryBuilder integration)
     */
    public function getIdentityMap(): IdentityMap
    {
        return $this->identityMap;
    }

    /**
     * Get the entity event manager
     */
    public function getEntityEventManager(): EntityEventManager
    {
        return $this->entityEventManager;
    }

    /**
     * Record a domain event for an entity
     */
    public function recordDomainEvent(object $entity, object $event): void
    {
        $this->entityEventManager->recordDomainEvent($entity, $event);
    }

    /**
     * Dispatch all domain events for an entity
     */
    public function dispatchDomainEventsForEntity(object $entity): void
    {
        $this->entityEventManager->dispatchDomainEventsForEntity($entity);
    }

    /**
     * Dispatch all domain events across all entities
     */
    public function dispatchAllDomainEvents(): void
    {
        $this->entityEventManager->dispatchAllDomainEvents();
    }

    /**
     * Get domain event statistics
     */
    public function getDomainEventStats(): array
    {
        return $this->entityEventManager->getDomainEventStats();
    }

    /**
     * Get profiling statistics if profiling is enabled
     */
    public function getProfilingStatistics(): ?array
    {
        $connection = $this->databaseManager->getConnection();

        if ($connection instanceof \App\Framework\Database\Profiling\ProfilingConnection) {
            return $connection->getProfilingStatistics();
        }

        return null;
    }

    /**
     * Get profiling summary if profiling is enabled
     */
    public function getProfilingSummary(): ?\App\Framework\Database\Profiling\ProfileSummary
    {
        $connection = $this->databaseManager->getConnection();

        if ($connection instanceof \App\Framework\Database\Profiling\ProfilingConnection) {
            return $connection->getProfilingSummary();
        }

        return null;
    }

    /**
     * Clear profiling data if profiling is enabled
     */
    public function clearProfilingData(): void
    {
        $connection = $this->databaseManager->getConnection();

        if ($connection instanceof \App\Framework\Database\Profiling\ProfilingConnection) {
            $connection->clearProfilingData();
        }
    }

    /**
     * Enable or disable profiling at runtime
     */
    public function setProfilingEnabled(bool $enabled): void
    {
        $connection = $this->databaseManager->getConnection();

        if ($connection instanceof \App\Framework\Database\Profiling\ProfilingConnection) {
            $connection->setProfilingEnabled($enabled);
        }
    }

    /**
     * Check if profiling is enabled
     */
    public function isProfilingEnabled(): bool
    {
        $connection = $this->databaseManager->getConnection();

        if ($connection instanceof \App\Framework\Database\Profiling\ProfilingConnection) {
            return $connection->isProfilingEnabled();
        }

        return false;
    }
}
