<?php

declare(strict_types=1);

namespace App\Framework\Reflection;

use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Reflection\Cache\MethodCache;
use App\Framework\Reflection\Collections\AttributeCollection;
use App\Framework\Reflection\Collections\ParameterCollection;
use App\Framework\Reflection\Support\AttributeHandler;

final readonly class WrappedReflectionMethod
{
    private AttributeHandler $attributeHandler;

    public function __construct(
        private ClassName $className,
        private string $methodName,
        private MethodCache $cache
    ) {
        $this->attributeHandler = new AttributeHandler();
    }

    public function getDeclaringClass(): ClassName
    {
        return $this->className;
    }

    public function getName(): string
    {
        return $this->methodName;
    }

    public function getParameters(): ParameterCollection
    {
        return $this->cache->getMethodParameters($this->className, $this->methodName);
    }

    /**
     * @deprecated Use getParameters() instead
     */
    public function getWrappedParameters(): ParameterCollection
    {
        return $this->getParameters();
    }

    // Erweiterte Parameter-Info als Array (für DI)
    public function getParameterInfo(): array
    {
        return $this->cache->getParameterInfo($this->className, $this->methodName);
    }

    public function getAttributes(?string $attributeClass = null): AttributeCollection
    {
        return $this->cache->getMethodAttributes($this->className, $this->methodName, $attributeClass);
    }

    public function getAttributeInstances(?string $attributeClass = null): array
    {
        $attributes = $this->cache->getMethodAttributes($this->className, $this->methodName, $attributeClass);

        return $this->attributeHandler->getInstances($attributes);
    }

    public function hasAttribute(string $attributeClass): bool
    {
        $attributes = $this->cache->getMethodAttributes($this->className, $this->methodName, $attributeClass);

        return $this->attributeHandler->hasAny($attributes);
    }

    public function getFirstAttribute(string $attributeClass): ?object
    {
        $attributes = $this->cache->getMethodAttributes($this->className, $this->methodName, $attributeClass);

        return $this->attributeHandler->getFirst($attributes);
    }

    /**
     * Get return type name for method
     */
    public function getReturnType(): ?string
    {
        return $this->cache->getReturnType($this->className, $this->methodName);
    }

    /**
     * Check if method is public
     */
    public function isPublic(): bool
    {
        // Get the actual reflection method to check visibility
        $reflectionMethod = new \ReflectionMethod($this->className->getFullyQualified(), $this->methodName);

        return $reflectionMethod->isPublic();
    }

    /**
     * Get method start line number
     */
    public function getStartLine(): int|false
    {
        $reflectionMethod = new \ReflectionMethod($this->className->getFullyQualified(), $this->methodName);

        return $reflectionMethod->getStartLine();
    }

    /**
     * Get number of parameters
     */
    public function getNumberOfParameters(): int
    {
        return $this->getParameters()->count();
    }
}
