<?php

declare(strict_types=1);

namespace App\Framework\Discovery\Enhanced\ValueObjects;

/**
 * Dependency Node representation
 *
 * Represents a single component in the dependency graph.
 */
final readonly class DependencyNode
{
    public function __construct(
        public string $id,
        public string $name,
        public ComponentType $type,
        public array $metadata = [],
        public float $weight = 1.0
    ) {
    }

    /**
     * Get node importance score based on type and metadata
     */
    public function getImportanceScore(): float
    {
        $score = $this->type->getWeight() * $this->weight;

        // Adjust based on metadata
        if (isset($this->metadata['usage_count'])) {
            $score += min(2.0, $this->metadata['usage_count'] * 0.1);
        }

        if (isset($this->metadata['is_core']) && $this->metadata['is_core']) {
            $score *= 1.5;
        }

        if (isset($this->metadata['is_deprecated']) && $this->metadata['is_deprecated']) {
            $score *= 0.5;
        }

        return $score;
    }

    /**
     * Check if this node represents a critical component
     */
    public function isCritical(): bool
    {
        return $this->getImportanceScore() > 2.0 ||
               ($this->metadata['is_core'] ?? false) ||
               in_array($this->type, [ComponentType::CONTROLLER, ComponentType::SERVICE]);
    }

    /**
     * Get component category for grouping
     */
    public function getCategory(): string
    {
        return match ($this->type) {
            ComponentType::CONTROLLER => 'presentation',
            ComponentType::SERVICE, ComponentType::FACTORY, ComponentType::BUILDER => 'business',
            ComponentType::REPOSITORY => 'data',
            ComponentType::MIDDLEWARE => 'infrastructure',
            ComponentType::COMMAND => 'console',
            ComponentType::EVENT => 'events',
            ComponentType::VALUE_OBJECT, ComponentType::ENUM => 'domain',
            ComponentType::INTERFACE, ComponentType::TRAIT => 'contracts',
            ComponentType::EXCEPTION => 'exceptions',
            ComponentType::DECORATOR, ComponentType::ADAPTER => 'patterns',
            default => 'other'
        };
    }

    /**
     * Get estimated memory usage of this component
     */
    public function getEstimatedMemoryUsage(): int
    {
        $baseUsage = match ($this->type) {
            ComponentType::CONTROLLER => 50 * 1024,      // 50KB
            ComponentType::SERVICE => 30 * 1024,         // 30KB
            ComponentType::REPOSITORY => 40 * 1024,      // 40KB
            ComponentType::MIDDLEWARE => 20 * 1024,      // 20KB
            ComponentType::COMMAND => 25 * 1024,         // 25KB
            ComponentType::EVENT => 5 * 1024,            // 5KB
            ComponentType::VALUE_OBJECT => 2 * 1024,     // 2KB
            ComponentType::ENUM => 1 * 1024,             // 1KB
            ComponentType::INTERFACE => 500,             // 500B
            ComponentType::TRAIT => 3 * 1024,            // 3KB
            ComponentType::FACTORY => 15 * 1024,         // 15KB
            ComponentType::BUILDER => 10 * 1024,         // 10KB
            ComponentType::DECORATOR => 8 * 1024,        // 8KB
            ComponentType::ADAPTER => 12 * 1024,         // 12KB
            ComponentType::EXCEPTION => 2 * 1024,        // 2KB
            default => 10 * 1024                         // 10KB
        };

        // Adjust based on metadata
        if (isset($this->metadata['complexity_score'])) {
            $baseUsage = (int)($baseUsage * (1 + $this->metadata['complexity_score'] * 0.5));
        }

        if (isset($this->metadata['line_count'])) {
            $baseUsage += (int)($this->metadata['line_count'] * 100); // 100 bytes per line
        }

        return $baseUsage;
    }

    /**
     * Get performance impact level
     */
    public function getPerformanceImpact(): string
    {
        return $this->type->getPerformanceImpact();
    }

    /**
     * Check if node has specific metadata
     */
    public function hasMetadata(string $key): bool
    {
        return isset($this->metadata[$key]);
    }

    /**
     * Get metadata value with default
     */
    public function getMetadata(string $key, mixed $default = null): mixed
    {
        return $this->metadata[$key] ?? $default;
    }

    /**
     * Convert to array representation
     */
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'type' => $this->type->value,
            'type_description' => $this->type->getDescription(),
            'weight' => $this->weight,
            'importance_score' => round($this->getImportanceScore(), 2),
            'is_critical' => $this->isCritical(),
            'category' => $this->getCategory(),
            'estimated_memory_usage' => $this->getEstimatedMemoryUsage(),
            'performance_impact' => $this->getPerformanceImpact(),
            'metadata' => $this->metadata,
        ];
    }

    /**
     * Create from array data
     */
    public static function fromArray(array $data): self
    {
        return new self(
            id: $data['id'],
            name: $data['name'],
            type: ComponentType::from($data['type'] ?? 'unknown'),
            metadata: $data['metadata'] ?? [],
            weight: $data['weight'] ?? 1.0
        );
    }

    /**
     * Create a simple node with minimal data
     */
    public static function simple(string $id, string $name, ComponentType $type): self
    {
        return new self($id, $name, $type);
    }

    /**
     * Create a critical node with high importance
     */
    public static function critical(string $id, string $name, ComponentType $type): self
    {
        return new self(
            id: $id,
            name: $name,
            type: $type,
            metadata: ['is_core' => true],
            weight: 2.0
        );
    }

    /**
     * Create node with complexity metadata
     */
    public static function withComplexity(
        string $id,
        string $name,
        ComponentType $type,
        float $complexity
    ): self {
        return new self(
            id: $id,
            name: $name,
            type: $type,
            metadata: ['complexity_score' => $complexity],
            weight: 1.0 + ($complexity * 0.5)
        );
    }

    /**
     * Create node with usage statistics
     */
    public static function withUsage(
        string $id,
        string $name,
        ComponentType $type,
        int $usageCount
    ): self {
        return new self(
            id: $id,
            name: $name,
            type: $type,
            metadata: ['usage_count' => $usageCount],
            weight: 1.0 + min(1.0, $usageCount * 0.1)
        );
    }
}
