#!/usr/bin/python3
"""Tests for slpkg.binaries.dependencies.Required (dependency resolver)."""

from slpkg.binaries.dependencies import Required


def make_required(
    data: dict,
    name: str,
    option_resolve_off: bool = False,
    full_requires: bool = False,
) -> Required:
    """Construct Required bypassing __init__ to avoid Repositories/config_load."""
    req: Required = object.__new__(Required)
    req.data = data
    req.name = name
    req.option_for_resolve_off = option_resolve_off
    req.full_requires = full_requires
    return req


# ---------------------------------------------------------------------------
# remove_deps
# ---------------------------------------------------------------------------


def test_remove_deps_all_present(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg")
    result = req.remove_deps(["libvpx", "x264"])
    assert result == ["libvpx", "x264"]


def test_remove_deps_filters_missing(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg")
    result = req.remove_deps(["libvpx", "nonexistent", "yasm"])
    assert result == ["libvpx", "yasm"]


def test_remove_deps_all_missing(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg")
    result = req.remove_deps(["ghost1", "ghost2"])
    assert result == []


def test_remove_deps_empty_input(sample_data: dict) -> None:
    req = make_required(sample_data, "bash")
    result = req.remove_deps([])
    assert result == []


def test_remove_deps_preserves_order(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg")
    result = req.remove_deps(["yasm", "bash", "libvpx"])
    assert result == ["yasm", "bash", "libvpx"]


# ---------------------------------------------------------------------------
# resolve
# ---------------------------------------------------------------------------


def test_resolve_option_off_returns_empty(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg", option_resolve_off=True)
    assert req.resolve() == ()


def test_resolve_name_not_in_data_returns_empty(sample_data: dict) -> None:
    req = make_required(sample_data, "nonexistent")
    assert req.resolve() == ()


def test_resolve_no_deps_returns_empty(sample_data: dict) -> None:
    req = make_required(sample_data, "bash")
    assert req.resolve() == ()


def test_resolve_single_level_deps(sample_data: dict) -> None:
    # x264 → ['yasm']  (yasm has no deps of its own)
    req = make_required(sample_data, "x264")
    result = req.resolve()
    assert result == ("yasm",)


def test_resolve_transitive_deps(sample_data: dict) -> None:
    # ffmpeg → [libvpx, x264]; x264 → [yasm]
    # After sub-resolution: [libvpx, x264, yasm]
    # Reversed: [yasm, x264, libvpx]
    req = make_required(sample_data, "ffmpeg")
    result = req.resolve()
    assert result == ("yasm", "x264", "libvpx")


def test_resolve_full_requires_skips_sub_deps(sample_data: dict) -> None:
    # full_requires=True: only direct deps, reversed
    req = make_required(sample_data, "ffmpeg", full_requires=True)
    result = req.resolve()
    # direct: [libvpx, x264] → reversed: [x264, libvpx]
    assert result == ("x264", "libvpx")


def test_resolve_deduplication(dep_data: dict) -> None:
    # app → [libA, libB]; libA → [shared]; libB → [shared]
    # After resolution: [libA, libB, shared]  (shared added once)
    # Reversed: [shared, libB, libA]
    req = make_required(dep_data, "app")
    result = req.resolve()
    assert result == ("shared", "libB", "libA")


def test_resolve_dep_not_in_data_is_skipped(sample_data: dict) -> None:
    # Manually inject a package that requires a ghost package
    data = dict(sample_data)
    data["mypkg"] = {
        "version": "1.0",
        "build": "1",
        "requires": ["ghost", "yasm"],
        "package": "mypkg-1.0-x86_64-1.txz",
    }
    req = make_required(data, "mypkg")
    result = req.resolve()
    # 'ghost' removed by remove_deps; yasm is kept; yasm has no sub-deps
    assert result == ("yasm",)


def test_resolve_returns_tuple(sample_data: dict) -> None:
    req = make_required(sample_data, "ffmpeg")
    assert isinstance(req.resolve(), tuple)
