#!/usr/bin/python3
"""Tests for slpkg.tree: render_tree and collect_transitive_names."""

from slpkg.tree import collect_transitive_names, render_tree


# ---------------------------------------------------------------------------
# render_tree — empty tree
# ---------------------------------------------------------------------------


def test_render_tree_empty_returns_empty_list() -> None:
    assert render_tree({}) == []


# ---------------------------------------------------------------------------
# render_tree — single node
# ---------------------------------------------------------------------------


def test_render_tree_single_node_uses_last_connector() -> None:
    lines = render_tree({"pkg-a": {}})
    assert len(lines) == 1
    assert lines[0].startswith("└─ ")
    assert "pkg-a" in lines[0]


def test_render_tree_single_node_ascii_fallback() -> None:
    lines = render_tree({"pkg-a": {}}, unicode=False)
    assert lines[0].startswith("\\- ")


# ---------------------------------------------------------------------------
# render_tree — multiple siblings
# ---------------------------------------------------------------------------


def test_render_tree_first_sibling_uses_branch_connector() -> None:
    lines = render_tree({"pkg-a": {}, "pkg-b": {}})
    assert lines[0].startswith("├─ ")
    assert lines[1].startswith("└─ ")


def test_render_tree_all_names_present() -> None:
    lines = render_tree({"pkg-a": {}, "pkg-b": {}, "pkg-c": {}})
    names = [l.strip().lstrip("├─└ ") for l in lines]
    assert any("pkg-a" in l for l in lines)
    assert any("pkg-b" in l for l in lines)
    assert any("pkg-c" in l for l in lines)


# ---------------------------------------------------------------------------
# render_tree — nested children
# ---------------------------------------------------------------------------


def test_render_tree_nested_child_indented() -> None:
    tree = {"parent": {"child": {}}}
    lines = render_tree(tree)
    assert len(lines) == 2
    assert "parent" in lines[0]
    assert "child" in lines[1]
    # Child must be indented (has prefix before connector)
    assert lines[1].startswith("   ")


def test_render_tree_nested_last_child_uses_last_connector() -> None:
    tree = {"parent": {"child": {}}}
    lines = render_tree(tree)
    assert "└─ " in lines[1]


def test_render_tree_pipe_prefix_for_non_last_parent() -> None:
    tree = {"parent-a": {"child": {}}, "parent-b": {}}
    lines = render_tree(tree)
    # child of parent-a should have pipe prefix since parent-a is not last
    child_line = next(l for l in lines if "child" in l)
    assert "│  " in child_line


# ---------------------------------------------------------------------------
# render_tree — direct_parents annotation
# ---------------------------------------------------------------------------


def test_render_tree_also_direct_annotation_at_depth_gt0() -> None:
    tree = {"parent": {"shared-dep": {}}}
    lines = render_tree(tree, direct_parents={"shared-dep"}, grey="", endc="")
    child_line = next(l for l in lines if "shared-dep" in l)
    assert "[also direct]" in child_line


def test_render_tree_no_annotation_at_depth_0() -> None:
    # shared-dep is at depth 0 (direct parent itself), no annotation
    tree = {"shared-dep": {}}
    lines = render_tree(tree, direct_parents={"shared-dep"})
    assert "[also direct]" not in lines[0]


# ---------------------------------------------------------------------------
# render_tree — color_fn and label_fn
# ---------------------------------------------------------------------------


def test_render_tree_color_fn_applied() -> None:
    lines = render_tree({"pkg": {}}, color_fn=lambda n: f"RED({n})")
    assert "RED(pkg)" in lines[0]


def test_render_tree_label_fn_applied() -> None:
    lines = render_tree({"pkg": {}}, label_fn=lambda n: f"{n}-1.0")
    assert "pkg-1.0" in lines[0]


def test_render_tree_label_fn_overrides_display_not_logic() -> None:
    # color_fn receives raw name, label_fn changes display only
    received: list[str] = []
    render_tree({"pkg": {}}, color_fn=lambda n: received.append(n) or "", label_fn=lambda n: "LABEL")
    assert received == ["pkg"]


# ---------------------------------------------------------------------------
# render_tree — ANSI colors in output
# ---------------------------------------------------------------------------


def test_render_tree_green_and_endc_wrapped() -> None:
    lines = render_tree({"pkg": {}}, green="[G]", endc="[E]")
    assert "[G]pkg[E]" in lines[0]


# ---------------------------------------------------------------------------
# collect_transitive_names — basic cases
# ---------------------------------------------------------------------------


def test_collect_transitive_names_empty_tree() -> None:
    assert collect_transitive_names({}) == set()


def test_collect_transitive_names_flat_tree_returns_empty() -> None:
    # Only depth-0 entries — nothing transitive
    assert collect_transitive_names({"pkg-a": {}, "pkg-b": {}}) == set()


def test_collect_transitive_names_one_level_deep() -> None:
    tree = {"parent": {"child-a": {}, "child-b": {}}}
    result = collect_transitive_names(tree)
    assert result == {"child-a", "child-b"}


def test_collect_transitive_names_two_levels_deep() -> None:
    tree = {"parent": {"child": {"grandchild": {}}}}
    result = collect_transitive_names(tree)
    assert result == {"child", "grandchild"}


def test_collect_transitive_names_deduplicates() -> None:
    tree = {
        "parent-a": {"shared": {}},
        "parent-b": {"shared": {}},
    }
    result = collect_transitive_names(tree)
    assert result == {"shared"}
