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

import subprocess
from pathlib import Path
from unittest.mock import MagicMock, patch

import pytest
from slpkg.health_check import HealthCheck


@pytest.fixture
def mock_config():
    """Mock config_load for HealthCheck."""
    with patch("slpkg.health_check.config_load") as mock:
        mock.cyan = ""
        mock.red = ""
        mock.endc = ""
        mock.bold = ""
        mock.log_packages = Path("/var/log/packages")
        yield mock


@pytest.fixture
def hc_inst(mock_config):
    """Fixture for HealthCheck instance with mocked dependencies."""
    with patch("slpkg.health_check.Utilities", autospec=True) as mock_utils_cls, \
         patch("slpkg.health_check.ViewProcess", autospec=True):
        inst = HealthCheck({"option_quiet": False}, packages=[])
        return inst


def test_run_hc_with_packages(hc_inst):
    """Test health-check with specific packages."""
    hc_inst.packages = ["pkg1"]
    hc_inst.utils.all_installed.return_value = {"pkg1": "pkg1-1.0-x86_64-1"}
    hc_inst.utils.apply_package_pattern.return_value = ["pkg1"]
    hc_inst.utils.split_package.return_value = {"tag": "SBo"}
    
    with patch("slpkg.health_check.Path.is_file", return_value=True), \
         patch.object(hc_inst, "_process_package_files", return_value={"file1": ["lib1"]}) as mock_proc, \
         patch.object(hc_inst, "_display_results"):
        hc_inst.run()
        assert mock_proc.call_count == 1


def test_is_elf_success(hc_inst, tmp_path):
    """Test _is_elf with a real ELF header."""
    elf_file = tmp_path / "test_bin"
    elf_file.write_bytes(b"\x7fELFsomecontent")
    assert hc_inst._is_elf(elf_file) is True


def test_is_elf_failure(hc_inst, tmp_path):
    """Test _is_elf with a non-ELF file."""
    text_file = tmp_path / "test.txt"
    text_file.write_text("not an elf")
    assert hc_inst._is_elf(text_file) is False


def test_check_ldd_not_found(hc_inst):
    """Test ldd parsing when libraries are missing."""
    mock_stdout = "libtest.so => not found\nlibexists.so => /lib/libexists.so (0x123)\n"
    mock_res = MagicMock()
    mock_res.stdout = mock_stdout
    
    with patch("subprocess.run", return_value=mock_res):
        missing = hc_inst._check_ldd(Path("/usr/bin/test"))
        assert missing == ["libtest.so"]


def test_check_ldd_all_found(hc_inst):
    """Test ldd parsing when all libraries are present."""
    mock_stdout = "libexists.so => /lib/libexists.so (0x123)\n"
    mock_res = MagicMock()
    mock_res.stdout = mock_stdout
    
    with patch("subprocess.run", return_value=mock_res):
        missing = hc_inst._check_ldd(Path("/usr/bin/test"))
        assert missing == []


def test_process_package_files(hc_inst, tmp_path):
    """Test scanning a package log for broken binaries."""
    pkg_log = tmp_path / "pkg-1.0"
    pkg_log.write_text("FILE LIST:\nusr/bin/broken\nusr/share/doc/readme.txt\n")
    
    with patch.object(hc_inst, "_is_elf", return_value=True), \
         patch.object(hc_inst, "_check_ldd", return_value=["libmissing.so"]):
        broken = hc_inst._process_package_files(pkg_log)
        assert "/usr/bin/broken" in broken
        assert broken["/usr/bin/broken"] == ["libmissing.so"]


def test_display_results_quiet(hc_inst, capsys):
    """Test results display in quiet mode."""
    hc_inst.options["option_quiet"] = True
    # New data structure: {pkg: {"files": {...}, "tag": str}}
    broken = {"pkg1": {"files": {"/usr/bin/bin1": ["lib1.so"]}, "tag": "SBo"}}
    
    hc_inst._display_results(broken)
    captured = capsys.readouterr()
    assert captured.out.strip() == "pkg1"


def test_display_results_normal(hc_inst, capsys):
    """Test results display in normal mode."""
    hc_inst.options["option_quiet"] = False
    # New data structure: {pkg: {"files": {...}, "tag": str}}
    broken = {"pkg1": {"files": {"/usr/bin/bin1": ["lib1.so"]}, "tag": "SBo"}}
    
    hc_inst._display_results(broken)
    captured = capsys.readouterr()
    assert "Found 1 packages" in captured.out
    assert "pkg1" in captured.out
    assert "[SBo]" in captured.out
    assert "/usr/bin/bin1" in captured.out
    assert "missing: lib1.so" in captured.out
