from typing import Generator, Any, Tuple, Optional
import networkx as nx
import logging
from ..model.point import Point
from ..model.vector import Vector


class GraphTraversal:
    def __init__(self, graph: nx.Graph):
        self.graph = graph
        self.logger = logging.getLogger(__name__)

    def dfs_traversal(
        self, start_node: Any
    ) -> Generator[Tuple[Point, Optional[Vector]], None, None]:
        visited_vector = set()
        for edge in nx.dfs_edges(self.graph, start_node):
            source_node, target_node = edge
            if source_node in visited_vector or target_node in visited_vector:
                continue

            # Convert to your Point and Vector objects
            source_data = self.graph.nodes[source_node]
            target_data = self.graph.nodes[target_node]

            point = None
            vector = None

            if self._is_point(source_data):
                point = Point.from_node_data(source_data)
            elif self._is_vector(source_data):
                vector = Vector.from_node_data(source_data)
                visited_vector.add(source_node)

            if self._is_point(target_data):
                point = Point.from_node_data(target_data)
            elif self._is_vector(target_data):
                vector = Vector.from_node_data(target_data)
                visited_vector.add(target_node)

            if point is None and vector is None:
                raise ValueError(f"Invalid node data: {source_data} or {target_data}")

            yield point, vector

    def _is_vector(self, node_data: dict) -> bool:
        return "Vector" in node_data["labels"]

    def _is_point(self, node_data: dict) -> bool:
        return "Point" in node_data["labels"]
