#!/usr/bin/python3
"""Tests for slpkg.depends.Depends pure data methods."""

from slpkg.depends import Depends


def make_depends(data: dict, option_for_pkg_version: bool = False) -> Depends:
    """Construct Depends bypassing __init__ (avoids config_load/Repositories)."""
    t: Depends = object.__new__(Depends)
    t.data = data
    t.bold = ""
    t.grey = ""
    t.yellow = ""
    t.red = "RED"  # non-empty so we can detect it in output
    t.cyan = ""
    t.endc = ""
    t.option_for_pkg_version = option_for_pkg_version
    # Mutable state used by the methods under test
    t.package_version = ""
    t.package_dependency_version = ""
    t.package_line = ""
    t.require_line = ""
    t.require_length = 0
    return t


# ---------------------------------------------------------------------------
# set_package_version(package)
# Sets self.package_version from data[package]['version'] or '' if not found.
# ---------------------------------------------------------------------------


def test_set_package_version_known(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_version("ffmpeg")
    assert t.package_version == "7.1"


def test_set_package_version_another_package(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_version("bash")
    assert t.package_version == "5.2.026"


def test_set_package_version_unknown_returns_empty(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_version("nonexistent")
    assert t.package_version == ""


def test_set_package_version_empty_data() -> None:
    t = make_depends({})
    t.set_package_version("ffmpeg")
    assert t.package_version == ""


# ---------------------------------------------------------------------------
# set_package_dependency_version(require)
# Sets self.package_dependency_version.
# If require in data → ' <version>';  else → ' (not included)'
# ---------------------------------------------------------------------------


def test_set_dep_version_known_require(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_dependency_version("yasm")
    assert "1.3.0" in t.package_dependency_version


def test_set_dep_version_another_known(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_dependency_version("bash")
    assert "5.2.026" in t.package_dependency_version


def test_set_dep_version_unknown_require(sample_data: dict) -> None:
    t = make_depends(sample_data)
    t.set_package_dependency_version("ghost")
    assert "(not included)" in t.package_dependency_version


def test_set_dep_version_empty_data() -> None:
    t = make_depends({})
    t.set_package_dependency_version("ffmpeg")
    assert "(not included)" in t.package_dependency_version


# ---------------------------------------------------------------------------
# set_the_package_line(package)
# Without version option: bold+cyan+name+endc
# With version option: bold+name+space+version+endc
# ---------------------------------------------------------------------------


def test_set_package_line_without_version_option(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=False)
    t.set_the_package_line("ffmpeg")
    assert "ffmpeg" in t.package_line


def test_set_package_line_with_version_option(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=True)
    t.set_the_package_line("ffmpeg")
    assert "ffmpeg" in t.package_line
    assert "7.1" in t.package_line


def test_set_package_line_with_version_unknown_package(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=True)
    t.set_the_package_line("nonexistent")
    assert "nonexistent" in t.package_line
    # version should be empty string → still no crash
    assert t.package_version == ""


def test_set_package_line_without_version_no_version_in_line(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=False)
    t.set_the_package_line("ffmpeg")
    # version should NOT appear when option is off
    assert "7.1" not in t.package_line


# ---------------------------------------------------------------------------
# set_the_package_require_line(require)
# require in data → no red color;  require NOT in data → red color
# Without version: just color+name+endc
# With version: color+name+endc+dep_version
# ---------------------------------------------------------------------------


def test_require_line_known_dep_no_red(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=False)
    t.set_the_package_require_line("yasm")
    # yasm is in data → color='' → no 'RED' in the line
    assert "RED" not in t.require_line
    assert "yasm" in t.require_line


def test_require_line_unknown_dep_has_red(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=False)
    t.set_the_package_require_line("ghost")
    # ghost not in data → color=self.red='RED'
    assert "RED" in t.require_line
    assert "ghost" in t.require_line


def test_require_line_with_version_known(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=True)
    t.require_length = 10
    t.set_the_package_require_line("yasm")
    assert "yasm" in t.require_line
    assert "1.3.0" in t.require_line


def test_require_line_with_version_unknown(sample_data: dict) -> None:
    t = make_depends(sample_data, option_for_pkg_version=True)
    t.require_length = 10
    t.set_the_package_require_line("ghost")
    assert "ghost" in t.require_line
    assert "(not included)" in t.require_line


# ---------------------------------------------------------------------------
# _build_dep_tree
# ---------------------------------------------------------------------------


def make_depends_tree(data: dict, view_missing_deps: bool = False) -> "Depends":
    """Minimal Depends instance for testing _build_dep_tree."""
    from slpkg.depends import Depends

    obj: Depends = object.__new__(Depends)
    obj.data = data
    obj.view_missing_deps = view_missing_deps
    return obj


def test_build_dep_tree_no_requires_returns_empty(sample_data: dict) -> None:
    """bash has an empty requires list → empty tree."""
    obj = make_depends_tree(sample_data)
    assert obj._build_dep_tree("bash") == {}


def test_build_dep_tree_single_level(sample_data: dict) -> None:
    """libvpx has no requires; x264 requires only yasm."""
    obj = make_depends_tree(sample_data)
    tree = obj._build_dep_tree("x264")
    assert tree == {"yasm": {}}


def test_build_dep_tree_two_level(sample_data: dict) -> None:
    """ffmpeg requires libvpx (no sub-deps) and x264 (which requires yasm)."""
    obj = make_depends_tree(sample_data)
    tree = obj._build_dep_tree("ffmpeg")
    assert "libvpx" in tree
    assert tree["libvpx"] == {}
    assert "x264" in tree
    assert tree["x264"] == {"yasm": {}}


def test_build_dep_tree_cycle_terminates() -> None:
    """Pathological cycle a → b → a must not recurse infinitely."""
    data = {
        "a": {"requires": ["b"], "version": "1.0"},
        "b": {"requires": ["a"], "version": "1.0"},
    }
    obj = make_depends_tree(data)
    result = obj._build_dep_tree("a")
    assert isinstance(result, dict)


def test_build_dep_tree_missing_dep_excluded_by_default(sample_data: dict) -> None:
    """A dep not in data is excluded when view_missing_deps=False."""
    sample_data["myapp"] = {"requires": ["ghost-lib"], "version": "1.0"}
    obj = make_depends_tree(sample_data, view_missing_deps=False)
    tree = obj._build_dep_tree("myapp")
    assert "ghost-lib" not in tree


def test_build_dep_tree_missing_dep_included_when_flag_set(sample_data: dict) -> None:
    """A dep not in data appears as a leaf node when view_missing_deps=True."""
    sample_data["myapp"] = {"requires": ["ghost-lib"], "version": "1.0"}
    obj = make_depends_tree(sample_data, view_missing_deps=True)
    tree = obj._build_dep_tree("myapp")
    assert "ghost-lib" in tree
    assert tree["ghost-lib"] == {}


def test_build_dep_tree_readme_token_excluded(sample_data: dict) -> None:
    """The SBO %README% token must never appear as a tree node."""
    sample_data["sbo-pkg"] = {"requires": ["%README%", "yasm"], "version": "1.0"}
    obj = make_depends_tree(sample_data)
    tree = obj._build_dep_tree("sbo-pkg")
    assert "%README%" not in tree
    assert "yasm" in tree
