<?php

declare(strict_types=1);

namespace App\Framework\Reflection\Builder;

use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\Reflection\CachedReflectionProvider;
use App\Framework\Reflection\ReflectionProvider;

/**
 * Factory for creating ReflectionBuilder instances
 *
 * This class provides static methods for creating ReflectionBuilder instances
 * for specific classes or methods, making it easier to use the builder pattern.
 */
final class ReflectionBuilderFactory
{
    /**
     * Create a new ReflectionBuilder for a class
     *
     * @param string|ClassName $className The class name to reflect
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function forClass(string|ClassName $className, ?ReflectionProvider $provider = null): ReflectionBuilder
    {
        $builder = self::create($provider);

        return $builder->forClass($className);
    }

    /**
     * Create a new ReflectionBuilder for a method
     *
     * @param string|ClassName $className The class name to reflect
     * @param string $methodName The method name to reflect
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function forMethod(
        string|ClassName $className,
        string $methodName,
        ?ReflectionProvider $provider = null
    ): ReflectionBuilder {
        $builder = self::create($provider);

        return $builder->forClass($className)->method($methodName);
    }

    /**
     * Create a new ReflectionBuilder for a class with a specific attribute
     *
     * @param string|ClassName $className The class name to reflect
     * @param string $attributeClass The attribute class to filter by
     * @param int $flags Optional flags for attribute lookup (ReflectionAttribute::IS_INSTANCEOF)
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function forClassWithAttribute(
        string|ClassName $className,
        string $attributeClass,
        int $flags = 0,
        ?ReflectionProvider $provider = null
    ): ReflectionBuilder {
        $builder = self::create($provider);

        return $builder->forClass($className)->withAttribute($attributeClass, $flags);
    }

    /**
     * Create a new ReflectionBuilder for a method with a specific attribute
     *
     * @param string|ClassName $className The class name to reflect
     * @param string $methodName The method name to reflect
     * @param string $attributeClass The attribute class to filter by
     * @param int $flags Optional flags for attribute lookup (ReflectionAttribute::IS_INSTANCEOF)
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function forMethodWithAttribute(
        string|ClassName $className,
        string $methodName,
        string $attributeClass,
        int $flags = 0,
        ?ReflectionProvider $provider = null
    ): ReflectionBuilder {
        $builder = self::create($provider);

        return $builder->forClass($className)
            ->method($methodName)
            ->withAttribute($attributeClass, $flags);
    }

    /**
     * Create a new ReflectionBuilder with filtered methods
     *
     * @param string|ClassName $className The class name to reflect
     * @param int $filter The filter to apply (e.g., \ReflectionMethod::IS_PUBLIC)
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function forClassWithFilteredMethods(
        string|ClassName $className,
        int $filter,
        ?ReflectionProvider $provider = null
    ): ReflectionBuilder {
        $builder = self::create($provider);

        return $builder->forClass($className)->filterMethods($filter);
    }

    /**
     * Create a new ReflectionBuilder
     *
     * @param ReflectionProvider|null $provider Optional custom reflection provider
     * @return ReflectionBuilder The reflection builder
     */
    public static function create(?ReflectionProvider $provider = null): ReflectionBuilder
    {
        $reflectionProvider = $provider ?? new CachedReflectionProvider();

        return new ReflectionBuilder($reflectionProvider);
    }
}
