from __future__ import annotations

import json
from collections import defaultdict, deque
from pathlib import Path


class EngineeringGraph:
    def __init__(self, links: list[dict[str, str]]) -> None:
        self.forward: dict[str, list[tuple[str, str]]] = defaultdict(list)
        for link in links:
            self.forward[link["source"]].append((link["target"], link["type"]))

    def downstream(self, start: str) -> list[str]:
        seen: set[str] = set()
        queue: deque[str] = deque([start])
        while queue:
            node = queue.popleft()
            for target, _link_type in self.forward.get(node, []):
                if target not in seen:
                    seen.add(target)
                    queue.append(target)
        seen.discard(start)
        return sorted(seen)


def main() -> None:
    data = json.loads(Path("data/digital_thread.json").read_text(encoding="utf-8"))
    graph = EngineeringGraph(data["links"])
    candidates = graph.downstream("REQ-LOAD")
    print("review_candidates_after_REQ_LOAD_change =", candidates)
    print("note = graph traversal identifies review candidates, not automatically invalid artifacts")
    assert candidates == ["ANA-STRESS-01", "DEC-B0-01", "RES-STRESS-01", "TEST-LOAD-01"]


if __name__ == "__main__":
    main()
