#!/usr/bin/python3
"""Tests for slpkg.all_repos.AllRepos."""

from unittest.mock import MagicMock, patch

import pytest

from slpkg.all_repos import AllRepos


def make_all_repos(
    priority: list[str] | None = None,
    repos: dict | None = None,
    options: dict | None = None,
    mode: str = "upgrade",
) -> AllRepos:
    """Construct AllRepos bypassing real config/Repositories/LoadData."""
    ua: AllRepos = object.__new__(AllRepos)
    ua.options = dict(options or {})
    ua.mode = mode
    ua.packages = []

    mock_repos = MagicMock()
    mock_repos.all_repos_priority = priority or []
    mock_repos.repositories = repos or {}
    mock_repos.sbo_repo_name = "sbo"
    mock_repos.ponce_repo_name = "ponce"
    ua.repos = mock_repos

    ua.red = ""
    ua.cyan = ""
    ua.endc = ""
    ua.load_data = MagicMock()
    ua.all_repos_confirm = "once"
    ua.sbo_repos = {"sbo", "ponce"}
    return ua


# ---------------------------------------------------------------------------
# priority_repos()
# ---------------------------------------------------------------------------


def test_priority_repos_returns_enabled_repos_in_order() -> None:
    repos = {
        "ponce": {"enable": True},
        "alien": {"enable": True},
        "slack": {"enable": False},
    }
    ua = make_all_repos(priority=["ponce", "alien", "slack"], repos=repos)
    result = ua.priority_repos()
    assert result == ["ponce", "alien"]


def test_priority_repos_falls_back_to_all_enabled_when_priority_empty() -> None:
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}, "slack": {"enable": False}}
    ua = make_all_repos(priority=[], repos=repos)
    result = ua.priority_repos()
    assert "ponce" in result
    assert "alien" in result
    assert "slack" not in result


def test_priority_repos_empty_when_all_disabled() -> None:
    repos = {"ponce": {"enable": False}, "alien": {"enable": False}}
    ua = make_all_repos(priority=["ponce", "alien"], repos=repos)
    assert ua.priority_repos() == []


def test_priority_repos_skips_unknown_repos() -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(priority=["ponce", "alien"], repos=repos)
    assert ua.priority_repos() == ["alien"]


def test_priority_repos_case_insensitive() -> None:
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}}
    ua = make_all_repos(priority=["PONCE", "Alien"], repos=repos)
    assert ua.priority_repos() == ["ponce", "alien"]


def test_priority_repos_preserves_priority_order() -> None:
    repos = {
        "alien": {"enable": True},
        "ponce": {"enable": True},
    }
    ua = make_all_repos(priority=["alien", "ponce"], repos=repos)
    assert ua.priority_repos() == ["alien", "ponce"]


# ---------------------------------------------------------------------------
# priority_repos() — --repos-priority override
# ---------------------------------------------------------------------------


def test_repos_priority_override_used_when_provided() -> None:
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}, "slack": {"enable": True}}
    ua = make_all_repos(
        priority=["slack", "ponce"],
        repos=repos,
        options={"option_repos_priority": ["alien", "ponce"]},
    )
    assert ua.priority_repos() == ["alien", "ponce"]


def test_repos_priority_override_ignores_toml_priority() -> None:
    """--repos-priority must win over the [ALL_REPOS] PRIORITY list."""
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}}
    ua = make_all_repos(
        priority=["ponce"],  # toml says ponce only
        repos=repos,
        options={"option_repos_priority": ["alien"]},
    )
    assert ua.priority_repos() == ["alien"]


def test_repos_priority_override_filters_disabled_repos() -> None:
    repos = {"ponce": {"enable": False}, "alien": {"enable": True}}
    ua = make_all_repos(
        repos=repos,
        options={"option_repos_priority": ["ponce", "alien"]},
    )
    assert ua.priority_repos() == ["alien"]


def test_repos_priority_override_case_insensitive() -> None:
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}}
    ua = make_all_repos(
        repos=repos,
        options={"option_repos_priority": ["PONCE", "ALIEN"]},
    )
    assert ua.priority_repos() == ["ponce", "alien"]


def test_repos_priority_override_unknown_repo_exits() -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos, options={"option_repos_priority": ["nonexistent"]})
    with pytest.raises(SystemExit):
        ua.run()


def test_repos_priority_override_absent_falls_back_to_toml() -> None:
    """No --repos-priority → existing PRIORITY list used."""
    repos = {"ponce": {"enable": True}, "alien": {"enable": True}}
    ua = make_all_repos(priority=["ponce"], repos=repos, options={})
    assert ua.priority_repos() == ["ponce"]


# ---------------------------------------------------------------------------
# _qualify_dep
# ---------------------------------------------------------------------------


def test_qualify_dep_with_known_repo_adds_suffix() -> None:
    assert AllRepos._qualify_dep("libvpx", {"libvpx": "alien"}) == "libvpx [alien]"


def test_qualify_dep_with_unknown_repo_returns_plain() -> None:
    assert AllRepos._qualify_dep("libvpx", {}) == "libvpx"


def test_qualify_dep_with_empty_repo_string_returns_plain() -> None:
    assert AllRepos._qualify_dep("libvpx", {"libvpx": ""}) == "libvpx"


# ---------------------------------------------------------------------------
# _conflict_packages
# ---------------------------------------------------------------------------


def test_conflict_packages_returns_pkg_in_multiple_repos() -> None:
    raw = [
        ("alien", {}, ["ffmpeg", "bash"], False),
        ("slack", {}, ["ffmpeg", "vlc"], False),
    ]
    result = AllRepos._conflict_packages(raw)
    assert "ffmpeg" in result
    assert "bash" not in result
    assert "vlc" not in result


def test_conflict_packages_empty_input_returns_empty_set() -> None:
    assert AllRepos._conflict_packages([]) == set()


def test_conflict_packages_no_conflicts_returns_empty_set() -> None:
    raw = [("alien", {}, ["ffmpeg"], False), ("slack", {}, ["bash"], False)]
    assert AllRepos._conflict_packages(raw) == set()


# ---------------------------------------------------------------------------
# _build_dep_ui_data
# ---------------------------------------------------------------------------


def test_build_dep_ui_data_qualifies_dep_names() -> None:
    ua = make_all_repos()
    dep_to_repo = {"libvpx": "alien", "x264": "alien"}
    repo_data_map = {"alien": ({"libvpx": {"v": "1"}, "x264": {"v": "2"}}, False)}
    combined, deps_for_ui = ua._build_dep_ui_data(
        ["libvpx", "x264"], dep_to_repo, repo_data_map, set()
    )
    assert "libvpx [alien]" in combined
    assert "x264 [alien]" in combined
    assert "libvpx [alien]" in deps_for_ui
    assert "x264 [alien]" in deps_for_ui


def test_build_dep_ui_data_excludes_auto_moved_from_ui_list() -> None:
    ua = make_all_repos()
    dep_to_repo = {"libvpx": "alien", "x264": "alien"}
    repo_data_map = {"alien": ({"libvpx": {}, "x264": {}}, False)}
    combined, deps_for_ui = ua._build_dep_ui_data(
        ["libvpx", "x264"], dep_to_repo, repo_data_map, {"libvpx"}
    )
    # libvpx is auto-moved → excluded from deps_for_ui, but still in combined_dep_data
    assert "libvpx [alien]" in combined
    assert "libvpx [alien]" not in deps_for_ui
    assert "x264 [alien]" in deps_for_ui


def test_build_dep_ui_data_skips_dep_with_unknown_repo_in_combined() -> None:
    """A dep whose repo is not in repo_data_map is absent from combined_dep_data
    (no pkg data to look up), but still present in deps_for_ui — ChooseDependencies
    will skip it gracefully with a warning because it won't be in its data dict."""
    ua = make_all_repos()
    dep_to_repo = {"libvpx": "missing_repo"}
    repo_data_map = {"alien": ({}, False)}
    combined, deps_for_ui = ua._build_dep_ui_data(
        ["libvpx"], dep_to_repo, repo_data_map, set()
    )
    assert combined == {}
    assert deps_for_ui == ["libvpx [missing_repo]"]


# ---------------------------------------------------------------------------
# _merge_binary_repos_data
# ---------------------------------------------------------------------------


def test_merge_binary_repos_data_single_repo() -> None:
    bin_data = [("alien", {"ffmpeg": {}}, ["ffmpeg"], ["libvpx"], ["ffmpeg"])]
    first, merged_data, merged_sel, merged_deps, pkg_to_repo, label = (
        AllRepos._merge_binary_repos_data(bin_data)
    )
    assert first == "alien"
    assert "ffmpeg" in merged_data
    assert "ffmpeg" in merged_sel
    assert "libvpx" in merged_deps
    assert pkg_to_repo["ffmpeg"] == "alien"
    assert label == "alien"


def test_merge_binary_repos_data_multiple_repos_merges_correctly() -> None:
    bin_data = [
        ("alien", {"ffmpeg": {}}, ["ffmpeg"], [], ["ffmpeg"]),
        ("slack", {"bash": {}}, ["bash"], ["libreadline"], ["bash"]),
    ]
    first, merged_data, merged_sel, merged_deps, pkg_to_repo, label = (
        AllRepos._merge_binary_repos_data(bin_data)
    )
    assert first == "alien"
    assert "ffmpeg" in merged_data and "bash" in merged_data
    assert set(merged_sel) == {"ffmpeg", "bash"}
    assert "libreadline" in merged_deps
    assert pkg_to_repo["ffmpeg"] == "alien"
    assert pkg_to_repo["bash"] == "slack"
    assert label == "alien, slack"


def test_merge_binary_repos_data_deduplicates_packages() -> None:
    """A package appearing in both repos' selected_packages is added only once."""
    bin_data = [
        ("alien", {"ffmpeg": {}}, ["ffmpeg"], [], ["ffmpeg"]),
        ("slack", {"ffmpeg": {}}, ["ffmpeg"], [], ["ffmpeg"]),
    ]
    _, _, merged_sel, _, _, _ = AllRepos._merge_binary_repos_data(bin_data)
    assert merged_sel.count("ffmpeg") == 1


# ---------------------------------------------------------------------------
# _validate_priority_override
# ---------------------------------------------------------------------------


def test_validate_priority_override_known_repos_does_not_exit() -> None:
    repos = {"alien": {"enable": True}, "slack": {"enable": True}}
    ua = make_all_repos(repos=repos)
    ua._validate_priority_override(["alien", "slack"])  # must not raise


def test_validate_priority_override_unknown_repo_exits(capsys) -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos)
    with pytest.raises(SystemExit) as exc:
        ua._validate_priority_override(["alien", "nonexistent"])
    assert exc.value.code == 1
    assert "nonexistent" in capsys.readouterr().out


def test_validate_priority_override_empty_list_does_not_exit() -> None:
    ua = make_all_repos(repos={"alien": {"enable": True}})
    ua._validate_priority_override([])  # must not raise


# ---------------------------------------------------------------------------
# _build_combined_data
# ---------------------------------------------------------------------------


def test_build_combined_data_single_repo() -> None:
    ua = make_all_repos()
    data = {"ffmpeg": {"version": "7.1"}, "libvpx": {"version": "1.13"}}
    raw = [("alien", data, ["ffmpeg", "libvpx"], False)]

    combined_data, combined_packages, pkg_to_repo, repo_data_map, conflicts = ua._build_combined_data(raw)

    # Keys are now qualified: "pkg [repo]" (cyan/endc are "" in tests)
    assert set(combined_data.keys()) == {"ffmpeg [alien]", "libvpx [alien]"}
    assert combined_packages == ["ffmpeg [alien]", "libvpx [alien]"]
    assert pkg_to_repo["ffmpeg [alien]"] == "alien"
    assert pkg_to_repo["libvpx [alien]"] == "alien"
    assert repo_data_map["alien"] == (data, False)
    assert conflicts["ffmpeg"] == ["alien"]


def test_build_combined_data_first_repo_wins_on_conflict() -> None:
    ua = make_all_repos()
    data1 = {"ffmpeg": {"version": "7.1"}}
    data2 = {"ffmpeg": {"version": "6.0"}}
    raw = [("alien", data1, ["ffmpeg"], False), ("slack", data2, ["ffmpeg"], False)]

    combined_data, combined_packages, pkg_to_repo, _, conflicts = ua._build_combined_data(raw)

    # Qualified key for the winning (alien) entry; slack is skipped (conflict).
    assert combined_data["ffmpeg [alien]"]["version"] == "7.1"
    assert pkg_to_repo["ffmpeg [alien]"] == "alien"
    assert "slack" in conflicts["ffmpeg"]
    assert len(combined_packages) == 1


def test_build_combined_data_no_conflicts_when_packages_unique() -> None:
    ua = make_all_repos()
    data1 = {"ffmpeg": {"version": "7.1"}}
    data2 = {"bash": {"version": "5.2"}}
    raw = [("alien", data1, ["ffmpeg"], False), ("slack", data2, ["bash"], False)]

    _, combined_packages, _, _, conflicts = ua._build_combined_data(raw)

    assert len(combined_packages) == 2
    assert all(len(repos) == 1 for repos in conflicts.values())


def test_build_combined_data_empty_raw_returns_empty_structures() -> None:
    ua = make_all_repos()

    combined_data, combined_packages, pkg_to_repo, repo_data_map, conflicts = ua._build_combined_data([])

    assert combined_data == {}
    assert combined_packages == []
    assert pkg_to_repo == {}
    assert repo_data_map == {}
    assert conflicts == {}


def test_build_combined_data_is_sbo_flag_stored_in_repo_data_map() -> None:
    ua = make_all_repos()
    data = {"vmpk": {"version": "0.9"}}
    raw = [("ponce", data, ["vmpk"], True)]

    _, _, _, repo_data_map, _ = ua._build_combined_data(raw)

    assert repo_data_map["ponce"] == (data, True)


# ---------------------------------------------------------------------------
# _resolve_selected_deps
# ---------------------------------------------------------------------------


def test_resolve_selected_deps_binary_repo_calls_required() -> None:
    ua = make_all_repos()
    data = {"ffmpeg": {"version": "7.1"}}
    package_to_repo = {"ffmpeg": "alien"}
    repo_data_map = {"alien": (data, False)}

    mock_required = MagicMock()
    mock_required.return_value.resolve.return_value = ("libvpx",)

    with patch("slpkg.all_repos.Required", mock_required):
        all_deps, dep_to_repo = ua._resolve_selected_deps(["ffmpeg"], package_to_repo, repo_data_map)

    assert "libvpx" in all_deps
    assert dep_to_repo["libvpx"] == "alien"


def test_resolve_selected_deps_sbo_repo_calls_requires() -> None:
    ua = make_all_repos()
    data = {"vmpk": {"version": "0.9"}}
    package_to_repo = {"vmpk": "ponce"}
    repo_data_map = {"ponce": (data, True)}

    mock_requires = MagicMock()
    mock_requires.return_value.resolve.return_value = ("sonivox",)

    with patch("slpkg.all_repos.Requires", mock_requires):
        all_deps, dep_to_repo = ua._resolve_selected_deps(["vmpk"], package_to_repo, repo_data_map)

    assert "sonivox" in all_deps
    assert dep_to_repo["sonivox"] == "ponce"


def test_resolve_selected_deps_deduplicates_shared_deps() -> None:
    ua = make_all_repos()
    data = {}
    package_to_repo = {"pkgA": "alien", "pkgB": "alien"}
    repo_data_map = {"alien": (data, False)}

    def side_effect(d, pkg, opts):
        m = MagicMock()
        m.resolve.return_value = ("shared",)
        return m

    with patch("slpkg.all_repos.Required", side_effect=side_effect):
        all_deps, _ = ua._resolve_selected_deps(["pkgA", "pkgB"], package_to_repo, repo_data_map)

    assert all_deps.count("shared") == 1


def test_resolve_selected_deps_empty_packages_returns_empty() -> None:
    ua = make_all_repos()
    all_deps, dep_to_repo = ua._resolve_selected_deps([], {}, {})
    assert all_deps == []
    assert dep_to_repo == {}


def test_resolve_selected_deps_strips_repo_suffix_from_key() -> None:
    """_resolve_selected_deps must use the plain name when looking up deps,
    even when the package key is qualified like 'ffmpeg [alien]'."""
    ua = make_all_repos()
    data = {"ffmpeg": {"version": "7.1"}}
    # Qualified key as produced by _build_combined_data
    package_to_repo = {"ffmpeg [alien]": "alien"}
    repo_data_map = {"alien": (data, False)}

    mock_required = MagicMock()
    mock_required.return_value.resolve.return_value = ("libvpx",)

    with patch("slpkg.all_repos.Required", mock_required):
        all_deps, dep_to_repo = ua._resolve_selected_deps(
            ["ffmpeg [alien]"], package_to_repo, repo_data_map
        )

    # Should have resolved using the plain name "ffmpeg", not "ffmpeg [alien]"
    mock_required.assert_called_once_with(data, "ffmpeg", ua.options)
    assert all_deps == ["libvpx"]
    assert dep_to_repo["libvpx"] == "alien"


def test_pkg_name_auto_moved_strips_suffix() -> None:
    """auto_moved detection compares _pkg_name(key) against deps_set (plain names).
    Regression test for bug where 'pkg [repo]' was compared directly to plain 'pkg'."""
    ua = make_all_repos()
    # deps_set contains plain names; selected_packages have qualified keys
    deps_set = {"libvpx", "ffmpeg"}
    selected_packages = ["ffmpeg [alien]", "vlc [alien]"]

    auto_moved = [p for p in selected_packages if ua._pkg_name(p) in deps_set]
    actual_packages = [p for p in selected_packages if ua._pkg_name(p) not in deps_set]
    auto_moved_set = {ua._pkg_name(p) for p in auto_moved}

    assert auto_moved == ["ffmpeg [alien]"]
    assert actual_packages == ["vlc [alien]"]
    assert auto_moved_set == {"ffmpeg"}  # plain name, matches keys in deps_for_ui


# ---------------------------------------------------------------------------
# _split_per_repo
# ---------------------------------------------------------------------------


def test_split_per_repo_single_repo_basic() -> None:
    ua = make_all_repos()
    data = {"ffmpeg": {}}
    raw_repo_data = [("alien", data, ["ffmpeg"], False)]
    package_to_repo = {"ffmpeg": "alien"}

    result = ua._split_per_repo(raw_repo_data, ["ffmpeg"], [], [], {}, package_to_repo)

    assert len(result) == 1
    repo_name, _, actual, final_deps, selected = result[0]
    assert repo_name == "alien"
    assert "ffmpeg" in actual
    assert "ffmpeg" in selected
    assert final_deps == []


def test_split_per_repo_skips_repo_with_no_selected_packages() -> None:
    ua = make_all_repos()
    raw_repo_data = [
        ("alien", {"ffmpeg": {}}, ["ffmpeg"], False),
        ("slack", {"bash": {}}, ["bash"], False),
    ]
    # Only ffmpeg is selected — bash was deselected
    package_to_repo = {"ffmpeg": "alien", "bash": "slack"}

    result = ua._split_per_repo(raw_repo_data, ["ffmpeg"], [], [], {}, package_to_repo)

    assert len(result) == 1
    assert result[0][0] == "alien"


def test_split_per_repo_auto_moved_goes_into_final_deps() -> None:
    ua = make_all_repos()
    data = {"ffmpeg": {}, "libvpx": {}}
    raw_repo_data = [("alien", data, ["ffmpeg", "libvpx"], False)]
    package_to_repo = {"ffmpeg": "alien", "libvpx": "alien"}
    dep_to_repo = {"libvpx": "alien"}

    result = ua._split_per_repo(raw_repo_data, ["ffmpeg"], ["libvpx"], [], dep_to_repo, package_to_repo)

    assert len(result) == 1
    _, _, actual, final_deps, selected = result[0]
    assert "ffmpeg" in actual
    assert "libvpx" in final_deps
    assert "libvpx" in selected  # auto-moved packages are part of selected_pkgs


def test_split_per_repo_user_deps_assigned_to_correct_repo() -> None:
    ua = make_all_repos()
    raw_repo_data = [
        ("alien", {"ffmpeg": {}, "libvpx": {}}, ["ffmpeg"], False),
        ("slack", {"bash": {}}, ["bash"], False),
    ]
    package_to_repo = {"ffmpeg": "alien", "bash": "slack"}
    dep_to_repo = {"libvpx": "alien"}

    result = ua._split_per_repo(
        raw_repo_data, ["ffmpeg", "bash"], [], ["libvpx"], dep_to_repo, package_to_repo
    )

    alien_result = next(r for r in result if r[0] == "alien")
    assert "libvpx" in alien_result[3]  # final_deps for alien


# ---------------------------------------------------------------------------
# _print_conflicts
# ---------------------------------------------------------------------------


def test_print_conflicts_no_conflicts_prints_nothing(capsys) -> None:
    ua = make_all_repos()
    ua.options = {}
    ua.repos.all_repos_priority = []
    conflicts = {"ffmpeg": ["alien"], "bash": ["slack"]}
    ua._print_conflicts(conflicts)
    assert capsys.readouterr().out == ""


def test_print_conflicts_multi_repo_prints_warning(capsys) -> None:
    ua = make_all_repos()
    ua.options = {}
    ua.repos.all_repos_priority = []
    conflicts = {"ffmpeg": ["alien", "slack"]}
    ua._print_conflicts(conflicts)
    out = capsys.readouterr().out
    assert "ffmpeg" in out
    assert "Warning" in out


def test_print_conflicts_shows_toml_order_when_no_priority(capsys) -> None:
    ua = make_all_repos()
    ua.options = {}
    ua.repos.all_repos_priority = []
    conflicts = {"ffmpeg": ["alien", "slack"]}
    ua._print_conflicts(conflicts)
    out = capsys.readouterr().out
    assert "repositories.toml" in out


def test_print_conflicts_shows_priority_order_when_option_set(capsys) -> None:
    ua = make_all_repos()
    ua.options = {"option_repos_priority": ["alien"]}
    ua.repos.all_repos_priority = []
    conflicts = {"ffmpeg": ["alien", "slack"]}
    ua._print_conflicts(conflicts)
    out = capsys.readouterr().out
    assert "PRIORITY" in out


def test_print_conflicts_uses_first_repo_as_winner(capsys) -> None:
    ua = make_all_repos()
    ua.options = {}
    ua.repos.all_repos_priority = []
    conflicts = {"ffmpeg": ["alien", "slack"]}
    ua._print_conflicts(conflicts)
    out = capsys.readouterr().out
    assert "using 'alien'" in out


# ---------------------------------------------------------------------------
# run() — early exit paths (no actual network/disk I/O)
# ---------------------------------------------------------------------------


def test_run_no_enabled_repos_prints_message(capsys) -> None:
    ua = make_all_repos(repos={})
    ua.options = {}
    ua.run()
    out = capsys.readouterr().out
    assert "No enabled" in out


def test_run_unknown_repos_priority_exits(capsys) -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos, options={"option_repos_priority": ["nonexistent"]})
    with pytest.raises(SystemExit):
        ua.run()
    out = capsys.readouterr().out
    assert "not found" in out


def test_run_all_repos_up_to_date_prints_message(capsys) -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos)
    ua.options = {}

    mock_upgrade = MagicMock()
    mock_upgrade.packages.return_value = []

    with patch("slpkg.all_repos.LoadData") as MockLD, \
         patch("slpkg.all_repos.Upgrade", return_value=mock_upgrade), \
         patch("slpkg.all_repos.ViewProcess"):
        ua.load_data = MockLD.return_value
        ua.load_data.load.return_value = {}
        ua.run()

    out = capsys.readouterr().out
    assert "up-to-date" in out.lower()


# ---------------------------------------------------------------------------
# _load_packages — upgrade mode
# ---------------------------------------------------------------------------


def test_load_packages_upgrade_includes_added_packages() -> None:
    """_Added. packages (NEW_PACKAGES) must be included with their plain name."""
    repos = {"slack": {"enable": True}}
    ua = make_all_repos(repos=repos, mode="upgrade")
    ua.options = {}

    data = {"fast_float": {"version": "6.1.0"}, "bash": {"version": "5.2"}}
    mock_upgrade = MagicMock()
    mock_upgrade.packages.return_value = ["bash", "fast_float_Added."]

    with patch("slpkg.all_repos.Upgrade", return_value=mock_upgrade), \
         patch("slpkg.all_repos.ViewProcess"):
        ua.load_data.load.return_value = data
        result = ua._load_packages(["slack"], MagicMock(), quiet=True)

    assert len(result) == 1
    _, _, packages, _ = result[0]
    assert "bash" in packages
    assert "fast_float" in packages
    assert "fast_float_Added." not in packages


def test_load_packages_upgrade_excludes_removed_packages() -> None:
    """_Removed. packages (REMOVE_PACKAGES) must be excluded in upgrade mode."""
    repos = {"slack": {"enable": True}}
    ua = make_all_repos(repos=repos, mode="upgrade")
    ua.options = {}

    data = {"bash": {"version": "5.2"}}
    mock_upgrade = MagicMock()
    mock_upgrade.packages.return_value = ["bash", "oldpkg_Removed."]

    with patch("slpkg.all_repos.Upgrade", return_value=mock_upgrade), \
         patch("slpkg.all_repos.ViewProcess"):
        ua.load_data.load.return_value = data
        result = ua._load_packages(["slack"], MagicMock(), quiet=True)

    assert len(result) == 1
    _, _, packages, _ = result[0]
    assert "bash" in packages
    assert "oldpkg" not in packages
    assert "oldpkg_Removed." not in packages


# ---------------------------------------------------------------------------
# _load_packages — install mode
# ---------------------------------------------------------------------------


def test_load_packages_install_mode_filters_by_search_term(capsys) -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos, mode="install")
    ua.packages = ["ffmpeg"]
    ua.options = {}

    data = {"ffmpeg": {"version": "7.1"}, "libvpx": {"version": "1.13"}, "ffmpeg-compat": {"version": "4.4"}}

    with patch("slpkg.all_repos.ViewProcess"):
        ua.load_data.load.return_value = data
        result = ua._load_packages(["alien"], MagicMock(), quiet=True)

    assert len(result) == 1
    _, _, packages, is_sbo = result[0]
    assert "ffmpeg" in packages
    assert "ffmpeg-compat" in packages
    assert "libvpx" not in packages
    assert not is_sbo


def test_load_packages_install_mode_no_match_returns_empty() -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos, mode="install")
    ua.packages = ["nonexistent"]
    ua.options = {}

    data = {"ffmpeg": {"version": "7.1"}}

    with patch("slpkg.all_repos.ViewProcess"):
        ua.load_data.load.return_value = data
        result = ua._load_packages(["alien"], MagicMock(), quiet=True)

    assert result == []


def test_run_install_mode_no_match_prints_message(capsys) -> None:
    repos = {"alien": {"enable": True}}
    ua = make_all_repos(repos=repos, mode="install")
    ua.packages = ["nonexistent"]
    ua.options = {}

    mock_vp = MagicMock()
    with patch("slpkg.all_repos.LoadData") as MockLD, \
         patch("slpkg.all_repos.ViewProcess", return_value=mock_vp):
        ua.load_data = MockLD.return_value
        ua.load_data.load.return_value = {"ffmpeg": {"version": "7.1"}}
        ua.run()

    out = capsys.readouterr().out
    assert "No packages found" in out
