#!/usr/bin/python3
"""Tests for slpkg/rebuild.py using pytest."""

import sys
from unittest.mock import MagicMock, patch
import pytest

from slpkg.rebuild import Rebuild

@pytest.fixture
def mock_dependencies():
    """Mock common dependencies for Rebuild."""
    with patch("slpkg.rebuild.Repositories") as mock_repos, \
         patch("slpkg.rebuild.Utilities") as mock_utils, \
         patch("slpkg.rebuild.LoadData") as mock_load, \
         patch("slpkg.rebuild.Choose") as mock_choose, \
         patch("slpkg.rebuild.config_load") as mock_config:

        mock_repos.return_value.sbo_repo_name = "sbo"
        mock_repos.return_value.ponce_repo_name = "ponce"
        mock_repos.return_value.slack_repo_name = "slack"

        mock_repos.return_value.repositories = {
            "sbo": {"repo_tag": "_SBo", "enable": True},
            "ponce": {"repo_tag": "_SBo", "enable": False},
            "slack": {"repo_tag": "", "enable": True}
        }

        yield {
            "repos": mock_repos.return_value,
            "utils": mock_utils.return_value,
            "load": mock_load.return_value,
            "choose": mock_choose.return_value,
            "config": mock_config
        }


def test_rebuild_no_packages(mock_dependencies):
    options = {"option_quiet": True}
    repository = "sbo"

    mock_dependencies["load"].load.return_value = {"pkg1": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "other": "other-1.0-x86_64-1"  # No _SBo tag
    }
    mock_dependencies["utils"].split_package.return_value = {"name": "other", "version": "1.0", "arch": "x86_64", "build": "1", "tag": ""}

    rebuild = Rebuild(options, repository)

    rebuild.run()
    assert mock_dependencies["load"].load.called


def test_rebuild_finds_packages(mock_dependencies):
    options = {"option_quiet": True}
    repository = "sbo"

    mock_dependencies["load"].load.return_value = {"pkg1": {}, "pkg2": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "pkg1": "pkg1-1.0-x86_64-1_SBo",
        "pkg2": "pkg2-2.0-x86_64-1_SBo",
        "other": "other-1.0-x86_64-1"
    }

    def mock_split(full_name):
        if "_SBo" in full_name:
            name = full_name.split("-")[0]
            return {"name": name, "tag": "_SBo"}
        return {"name": "other", "tag": ""}

    mock_dependencies["utils"].split_package.side_effect = mock_split

    rebuild = Rebuild(options, repository)

    with patch("slpkg.rebuild.Slackbuilds") as mock_sb:
        rebuild.run()
        assert mock_sb.called
        args, kwargs = mock_sb.call_args
        assert sorted(args[2]) == ["pkg1", "pkg2"]


def test_rebuild_dry_run(mock_dependencies):
    options = {"option_quiet": True, "option_check": True}
    repository = "sbo"

    mock_dependencies["load"].load.return_value = {"pkg1": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "pkg1": "pkg1-1.0-x86_64-1_SBo"
    }
    mock_dependencies["utils"].split_package.return_value = {"name": "pkg1", "tag": "_SBo"}

    rebuild = Rebuild(options, repository)

    with patch("slpkg.rebuild.View") as mock_view:
        rebuild.run()
        assert mock_view.return_value.install_upgrade_packages.called
        assert rebuild.options["option_reinstall"] is True


def test_rebuild_selection(mock_dependencies):
    options = {"option_quiet": True, "option_select": True}
    repository = "sbo"

    mock_dependencies["load"].load.return_value = {"pkg1": {}, "pkg2": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "pkg1": "pkg1-1.0-x86_64-1_SBo",
        "pkg2": "pkg2-2.0-x86_64-1_SBo"
    }
    mock_dependencies["utils"].split_package.side_effect = [
        {"name": "pkg1", "tag": "_SBo"},
        {"name": "pkg2", "tag": "_SBo"}
    ]
    mock_dependencies["choose"].packages.return_value = ["pkg1"]

    rebuild = Rebuild(options, repository)

    with patch("slpkg.rebuild.Slackbuilds") as mock_sb:
        rebuild.run()
        assert mock_sb.called
        args, kwargs = mock_sb.call_args
        assert args[2] == ["pkg1"]


def test_rebuild_switches_from_slack_to_sbo(mock_dependencies):
    options = {"option_quiet": True}
    repository = "slack"  # Default repo is slack

    mock_dependencies["repos"].repositories["sbo"]["enable"] = True
    mock_dependencies["load"].load.return_value = {"pkg_sbo": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "pkg_sbo": "pkg_sbo-1.0-x86_64-1_SBo"
    }
    mock_dependencies["utils"].split_package.return_value = {"name": "pkg_sbo", "tag": "_SBo"}

    rebuild = Rebuild(options, repository)

    assert rebuild.repository == "sbo"

    with patch("slpkg.rebuild.Slackbuilds") as mock_sb:
        rebuild.run()
        assert mock_sb.called
        assert mock_sb.call_args[0][0] == "sbo"


def test_rebuild_rejects_binary_repo(mock_dependencies, capsys):
    options = {"option_quiet": True}
    repository = "alien"  # Binary repo

    mock_dependencies["repos"].repositories = {
        "sbo": {"repo_tag": "_SBo", "enable": True},
        "ponce": {"repo_tag": "_SBo", "enable": False},
        "slack": {"repo_tag": "", "enable": True},
        "alien": {"repo_tag": "_alien", "enable": True},
    }

    rebuild = Rebuild(options, repository)
    rebuild.run()

    captured = capsys.readouterr()
    assert "Error" in captured.out
    assert "reinstall" in captured.out


def test_rebuild_ponce_repo(mock_dependencies):
    options = {"option_quiet": True}
    repository = "ponce"

    mock_dependencies["repos"].repositories["ponce"]["enable"] = True
    mock_dependencies["load"].load.return_value = {"pkg1": {}}
    mock_dependencies["utils"].all_installed.return_value = {
        "pkg1": "pkg1-1.0-x86_64-1_SBo"
    }
    mock_dependencies["utils"].split_package.return_value = {"name": "pkg1", "tag": "_SBo"}

    rebuild = Rebuild(options, repository)

    with patch("slpkg.rebuild.Slackbuilds") as mock_sb:
        rebuild.run()
        assert mock_sb.called
        assert mock_sb.call_args[0][0] == "ponce"
