import pytest

from blends.models import (
    Graph,
    NId,
)
from blends.syntax.readers.python.parameter import (
    _extract_annotation_class_names,
)


def _make_identifier_graph(name: str) -> tuple[Graph, NId]:
    g = Graph()
    g.add_node("1", label_type="identifier", label_text=name)
    return g, "1"


def _make_attribute_graph(obj: str, attr: str) -> tuple[Graph, NId]:
    g = Graph()
    g.add_node("1", label_type="attribute", label_field_attribute="3")
    g.add_node("2", label_type="identifier", label_text=obj)
    g.add_node("3", label_type="identifier", label_text=attr)
    g.add_edge("1", "2", label_ast="AST")
    g.add_edge("1", "3", label_ast="AST")
    return g, "1"


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_simple_class_name() -> None:
    g, root = _make_identifier_graph("Foo")
    assert _extract_annotation_class_names(g, root) == {"Foo"}

    g2, root2 = _make_identifier_graph("int")
    assert _extract_annotation_class_names(g2, root2) == {"int"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_none_returns_empty() -> None:
    g, root = _make_identifier_graph("None")
    assert _extract_annotation_class_names(g, root) == set()


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_forward_ref_string() -> None:
    g = Graph()
    g.add_node("1", label_type="string", label_text='"Foo"')
    assert _extract_annotation_class_names(g, "1") == {"Foo"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_qualified_forward_ref_string_returns_last_segment() -> None:
    g = Graph()
    g.add_node("1", label_type="string", label_text='"module.Foo"')
    assert _extract_annotation_class_names(g, "1") == {"Foo"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_qualified_name_returns_last_segment() -> None:
    g, root = _make_attribute_graph("pkg", "Foo")
    assert _extract_annotation_class_names(g, root) == {"Foo"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_union_with_none() -> None:
    g = Graph()
    g.add_node("1", label_type="binary_operator")
    g.add_node("2", label_type="identifier", label_text="Counter")
    g.add_node("3", label_type="|", label_text="|")
    g.add_node("4", label_type="identifier", label_text="None")
    g.add_edge("1", "2", label_ast="AST")
    g.add_edge("1", "3", label_ast="AST")
    g.add_edge("1", "4", label_ast="AST")
    result = _extract_annotation_class_names(g, "1")
    assert result == {"Counter"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_type_wrapper_is_transparent() -> None:
    g = Graph()
    g.add_node("1", label_type="type")
    g.add_node("2", label_type="identifier", label_text="Counter")
    g.add_edge("1", "2", label_ast="AST")
    assert _extract_annotation_class_names(g, "1") == {"Counter"}


@pytest.mark.blends_test_group("stack_unittesting")
def test_extract_unknown_node_type_returns_empty() -> None:
    g = Graph()
    g.add_node("1", label_type="tuple_type", label_text="tuple[int, str]")
    assert _extract_annotation_class_names(g, "1") == set()
