<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Graph;

final class DependencyGraph
{
    private array $nodes = [];
    private array $edges = [];

    public function addNode(DependencyNode $node): void
    {
        $this->nodes[$node->id()] = $node;
    }

    public function addEdge(DependencyEdge $edge): void
    {
        $this->edges[] = $edge;
        if (!isset($this->nodes[$edge->from()])) {
            $this->addNode(new DependencyNode($edge->from()));
        }
        if (!isset($this->nodes[$edge->to()])) {
            $this->addNode(new DependencyNode($edge->to()));
        }
    }

    public function nodes(): array { return array_values($this->nodes); }
    public function edges(): array { return $this->edges; }

    public function dependenciesOf(string $id): array
    {
        return array_values(array_map(
            static fn (DependencyEdge $edge): string => $edge->to(),
            array_filter($this->edges, static fn (DependencyEdge $edge): bool => $edge->from() === $id)
        ));
    }

    public function dependentsOf(string $id): array
    {
        return array_values(array_map(
            static fn (DependencyEdge $edge): string => $edge->from(),
            array_filter($this->edges, static fn (DependencyEdge $edge): bool => $edge->to() === $id)
        ));
    }

    public function toArray(): array
    {
        return [
            'nodes' => array_map(static fn (DependencyNode $node): array => $node->toArray(), $this->nodes()),
            'edges' => array_map(static fn (DependencyEdge $edge): array => $edge->toArray(), $this->edges),
        ];
    }
}
