from __future__ import annotations

"""Basic structural graph builder.

This builder turns the hierarchical :class:`DocumentTree` into a simple
:class:`DocumentGraph` containing nodes for each document node and edges
for parent/child and next-sibling relationships.
"""

from typing import Dict, List, Optional

from ..core.models import DocumentGraph, DocumentNode, GraphEdge, GraphNode
from .base import BaseGraphBuilder


class StructuralGraphBuilder(BaseGraphBuilder):
    """Graph builder that encodes only document structure.

    Semantic enrichment (entities, concepts, etc.) can be added later as
    separate builders that extend or augment this graph.
    """

    def supports(self, tree) -> bool:  # type: ignore[override]
        # For v0.1 we accept any tree.
        return True

    def build(self, tree) -> DocumentGraph:  # type: ignore[override]
        nodes: Dict[str, GraphNode] = {}
        edges: List[GraphEdge] = []

        def visit(node: DocumentNode, parent: Optional[DocumentNode] = None, prev_sibling: Optional[DocumentNode] = None) -> None:
            if node.id not in nodes:
                nodes[node.id] = GraphNode(
                    id=node.id,
                    node_type=node.node_type,
                    label=node.text,
                    metadata=dict(node.metadata),
                )

            if parent is not None:
                edges.append(
                    GraphEdge(
                        source=parent.id,
                        target=node.id,
                        edge_type="parent_of",
                        metadata={},
                    )
                )

            if prev_sibling is not None:
                edges.append(
                    GraphEdge(
                        source=prev_sibling.id,
                        target=node.id,
                        edge_type="next_sibling",
                        metadata={},
                    )
                )

            last: Optional[DocumentNode] = None
            for child in node.children:
                visit(child, parent=node, prev_sibling=last)
                last = child

        visit(tree.root, parent=None, prev_sibling=None)

        return DocumentGraph(
            nodes=list(nodes.values()),
            edges=edges,
            metadata={"source_id": tree.metadata.get("source_id")},
        )

