<?php

declare(strict_types=1);

namespace App\Framework\Router\ValueObjects;

use ArrayIterator;
use Countable;
use IteratorAggregate;

/**
 * Type-safe collection of method parameters
 */
final readonly class ParameterCollection implements IteratorAggregate, Countable
{
    /** @var array<MethodParameter> */
    private array $parameters;

    public function __construct(MethodParameter ...$parameters)
    {
        $this->parameters = $parameters;
    }

    /**
     * @return ArrayIterator<int, MethodParameter>
     */
    public function getIterator(): ArrayIterator
    {
        return new ArrayIterator($this->parameters);
    }

    public function count(): int
    {
        return count($this->parameters);
    }

    public function isEmpty(): bool
    {
        return empty($this->parameters);
    }

    /**
     * Get parameter by name
     */
    public function getByName(string $name): ?MethodParameter
    {
        foreach ($this->parameters as $parameter) {
            if ($parameter->name === $name) {
                return $parameter;
            }
        }

        return null;
    }

    /**
     * Get all required parameters
     */
    public function getRequired(): self
    {
        $required = array_filter(
            $this->parameters,
            fn (MethodParameter $param) => $param->isRequired()
        );

        return new self(...$required);
    }

    /**
     * Get all builtin type parameters
     */
    public function getBuiltins(): self
    {
        $builtins = array_filter(
            $this->parameters,
            fn (MethodParameter $param) => $param->isBuiltin
        );

        return new self(...$builtins);
    }

    /**
     * Filter by type
     */
    public function filterByType(string $type): self
    {
        $filtered = array_filter(
            $this->parameters,
            fn (MethodParameter $param) => $param->isOfType($type)
        );

        return new self(...$filtered);
    }

    /**
     * Convert to legacy array format for backward compatibility
     * @deprecated Use object methods instead
     * @return array<array<string, mixed>>
     */
    public function toLegacyArray(): array
    {
        return array_map(
            fn (MethodParameter $param) => $param->toArray(),
            $this->parameters
        );
    }

    /**
     * @return array<MethodParameter>
     */
    public function toArray(): array
    {
        return $this->parameters;
    }
}
