module RBS
  # AncestorGraph is a utility class that helps iterating through ancestors and decendants of a class/module
  #
  # ```ruby
  # graph = AncestorGraph.new(env: env, ancestor_builder: ancestor_builder)
  #
  # graph.each_parent(AncestorGraph::InstanceNode.new(type_name: TypeName("::Object")))
  # graph.each_ancestor(AncestorGraph::InstanceNode.new(type_name: TypeName("::Object")))
  #
  # graph.each_child(AncestorGraph::InstanceNode.new(type_name: TypeName("::Object")))
  # graph.each_descendant(AncestorGraph::InstanceNode.new(type_name: TypeName("::Object")))
  # ```
  #
  # Note that the class works for class/module declarations.
  # All of the *alias* classes/modules are ignored.
  #
  # * Alias classes/modules doesn't count as a parent nor child
  # * Passing alias classes/modules to the method doesn't yield anything
  #
  class AncestorGraph
    class InstanceNode
      attr_reader type_name: TypeName
      def initialize: (type_name: TypeName) -> void
    end

    class SingletonNode
      attr_reader type_name: TypeName
      def initialize: (type_name: TypeName) -> void
    end

    type node = InstanceNode | SingletonNode

    attr_reader env: Environment
    attr_reader ancestor_builder: DefinitionBuilder::AncestorBuilder
    attr_reader parents: Hash[node, Set[node]]
    attr_reader children: Hash[node, Set[node]]

    def initialize: (env: Environment, ?ancestor_builder: DefinitionBuilder::AncestorBuilder) -> void

    def each_parent: (node) { (node) -> void } -> void
                   | (node) -> Enumerator[node, void]

    def each_ancestor: (node, ?yielded: Set[node]) { (node) -> void } -> void
                     | (node) -> Enumerator[node, void]

    def each_child: (node) { (node) -> void } -> void
                  | (node) -> Enumerator[node, void]

    def each_descendant: (node, ?yielded: Set[node]) { (node) -> void } -> void
                       | (node) -> Enumerator[node, void]

    private

    def build: () -> void

    def build_ancestors: (node, DefinitionBuilder::AncestorBuilder::OneAncestors) -> void

    def register: (parent: node, child: node) -> void
  end
end
