<?php

declare(strict_types=1);

namespace App\Framework\DI\Dependency;

use App\Framework\Core\ValueObjects\ClassName;
use App\Framework\DI\Container;

/**
 * Represents cached information for a single constructor parameter
 */
final readonly class ParameterCacheInfo
{
    private function __construct(
        public DependencyType $type,
        public mixed $value = null,
        public ?ClassName $className = null
    ) {
    }

    /**
     * Create cache info for default value parameter
     */
    public static function default(mixed $value): self
    {
        return new self(DependencyType::DEFAULT, $value);
    }

    /**
     * Create cache info for null parameter
     */
    public static function null(): self
    {
        return new self(DependencyType::NULL);
    }

    /**
     * Create cache info for dependency parameter
     */
    public static function dependency(ClassName $className): self
    {
        return new self(DependencyType::DEPENDENCY, null, $className);
    }

    /**
     * Create cache info for nullable dependency parameter
     */
    public static function nullableDependency(ClassName $className): self
    {
        return new self(DependencyType::NULLABLE_DEPENDENCY, null, $className);
    }

    /**
     * Create from legacy cache array format
     */
    public static function fromArray(array $cacheInfo): self
    {
        $type = DependencyType::from($cacheInfo['type']);

        return match ($type) {
            DependencyType::DEFAULT => self::default($cacheInfo['value']),
            DependencyType::NULL => self::null(),
            DependencyType::DEPENDENCY => self::dependency(ClassName::create($cacheInfo['class'])),
            DependencyType::NULLABLE_DEPENDENCY => self::nullableDependency(ClassName::create($cacheInfo['class'])),
        };
    }

    /**
     * Convert to legacy array format (for backward compatibility)
     */
    public function toArray(): array
    {
        return match ($this->type) {
            DependencyType::DEFAULT => [
                'type' => $this->type->value,
                'value' => $this->value,
            ],
            DependencyType::NULL => [
                'type' => $this->type->value,
            ],
            DependencyType::DEPENDENCY, DependencyType::NULLABLE_DEPENDENCY => [
                'type' => $this->type->value,
                'class' => $this->className?->getFullyQualified(),
            ],
        };
    }

    /**
     * Check if this parameter has a class dependency
     */
    public function hasClassDependency(): bool
    {
        return $this->className !== null;
    }

    /**
     * Check if this parameter has a specific class dependency
     */
    public function dependsOn(ClassName $className): bool
    {
        return $this->className !== null && $this->className->equals($className);
    }

    /**
     * Get the resolved value for this parameter
     */
    public function resolveValue(Container $container): mixed
    {
        return match ($this->type) {
            DependencyType::DEFAULT => $this->value,
            DependencyType::NULL => null,
            DependencyType::DEPENDENCY, DependencyType::NULLABLE_DEPENDENCY =>
                $container->get($this->className->getFullyQualified()),
        };
    }
}
