#!/usr/bin/python3
"""Tests for slpkg.list_files.ListFiles."""

from pathlib import Path
from unittest.mock import MagicMock

from slpkg.list_files import ListFiles


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

PKG_FULL = "ffmpeg-6.1-x86_64-1_SBo"

PKG_LOG_CONTENT = """\
PACKAGE NAME:  ffmpeg-6.1-x86_64-1_SBo
COMPRESSED PACKAGE SIZE:     12 M
UNCOMPRESSED PACKAGE SIZE:   45 M
PACKAGE LOCATION: ./
PACKAGE DESCRIPTION:
ffmpeg: ffmpeg
FILE LIST:
./
install/
install/slack-desc
./usr/bin/ffmpeg
./usr/lib64/libavcodec.so
./usr/share/doc/ffmpeg/README
usr/include/ffmpeg/avcodec.h
"""


def make_list_files(
    log_packages: Path,
    packages: list[str],
    *,
    quiet: bool = False,
    no_case: bool = False,
) -> ListFiles:
    """Construct ListFiles bypassing __init__ (avoids config_load)."""
    obj: ListFiles = object.__new__(ListFiles)
    obj.packages = packages
    obj.log_packages = log_packages
    obj.grey = ""
    obj.green = ""
    obj.red = ""
    obj.endc = ""
    obj.option_quiet = quiet
    obj.option_no_case = no_case
    obj.utils = MagicMock()
    obj.pkg_validator = MagicMock()
    return obj


def write_pkg_log(log_packages: Path, full_name: str, content: str) -> None:
    log_packages.mkdir(parents=True, exist_ok=True)
    (log_packages / full_name).write_text(content, encoding="utf-8")


# ---------------------------------------------------------------------------
# _read_file_list
# ---------------------------------------------------------------------------


def test_read_file_list_returns_absolute_paths(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, [])
    files = obj._read_file_list(PKG_FULL)
    assert "/usr/bin/ffmpeg" in files
    assert "/usr/lib64/libavcodec.so" in files
    assert "/usr/share/doc/ffmpeg/README" in files


def test_read_file_list_normalises_dot_slash_prefix(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, [])
    files = obj._read_file_list(PKG_FULL)
    # ./usr/bin/ffmpeg → /usr/bin/ffmpeg (no leading dot)
    assert all(not f.startswith("./") for f in files)


def test_read_file_list_normalises_relative_path(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, [])
    files = obj._read_file_list(PKG_FULL)
    # usr/include/... → /usr/include/...
    assert "/usr/include/ffmpeg/avcodec.h" in files


def test_read_file_list_skips_directories(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, [])
    files = obj._read_file_list(PKG_FULL)
    assert not any(f.endswith("/") for f in files)


def test_read_file_list_skips_install_scripts(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, [])
    files = obj._read_file_list(PKG_FULL)
    assert not any("install/" in f for f in files)


def test_read_file_list_no_file_list_section_returns_empty(tmp_path: Path) -> None:
    content = "PACKAGE NAME: foo\nsome other content\n"
    write_pkg_log(tmp_path, PKG_FULL, content)
    obj = make_list_files(tmp_path, [])
    assert obj._read_file_list(PKG_FULL) == []


# ---------------------------------------------------------------------------
# _find_installed — case-sensitive (delegates to utils)
# ---------------------------------------------------------------------------


def test_find_installed_case_sensitive_delegates_to_utils(tmp_path: Path) -> None:
    obj = make_list_files(tmp_path, [], no_case=False)
    obj.utils.is_package_installed.return_value = PKG_FULL
    result = obj._find_installed("ffmpeg")
    obj.utils.is_package_installed.assert_called_once_with("ffmpeg")
    assert result == PKG_FULL


def test_find_installed_case_sensitive_not_found_returns_empty(tmp_path: Path) -> None:
    obj = make_list_files(tmp_path, [], no_case=False)
    obj.utils.is_package_installed.return_value = ""
    assert obj._find_installed("nonexistent") == ""


# ---------------------------------------------------------------------------
# _find_installed — case-insensitive (scans log_packages dir)
# ---------------------------------------------------------------------------


def test_find_installed_no_case_finds_package(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, "")
    obj = make_list_files(tmp_path, [], no_case=True)
    obj.utils.split_package.return_value = {"name": "ffmpeg"}
    result = obj._find_installed("FFMPEG")
    assert result == PKG_FULL


def test_find_installed_no_case_not_found_returns_empty(tmp_path: Path) -> None:
    write_pkg_log(tmp_path, PKG_FULL, "")
    obj = make_list_files(tmp_path, [], no_case=True)
    obj.utils.split_package.return_value = {"name": "ffmpeg"}
    assert obj._find_installed("vlc") == ""


# ---------------------------------------------------------------------------
# run() — not found calls pkg_validator
# ---------------------------------------------------------------------------


def test_run_not_found_calls_pkg_validator(tmp_path: Path) -> None:
    obj = make_list_files(tmp_path, ["nonexistent"])
    obj.utils.is_package_installed.return_value = ""
    obj.run()
    obj.pkg_validator.is_package_installed.assert_called_once_with(["nonexistent"])


# ---------------------------------------------------------------------------
# run() — quiet mode
# ---------------------------------------------------------------------------


def test_run_quiet_prints_file_paths_only(tmp_path: Path, capsys) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, ["ffmpeg"], quiet=True)
    obj.utils.is_package_installed.return_value = PKG_FULL
    obj.run()
    out = capsys.readouterr().out
    assert "/usr/bin/ffmpeg" in out
    assert "Total:" not in out
    assert "Files installed by" not in out


# ---------------------------------------------------------------------------
# run() — normal mode
# ---------------------------------------------------------------------------


def test_run_normal_prints_header_and_total(tmp_path: Path, capsys) -> None:
    write_pkg_log(tmp_path, PKG_FULL, PKG_LOG_CONTENT)
    obj = make_list_files(tmp_path, ["ffmpeg"])
    obj.utils.is_package_installed.return_value = PKG_FULL
    obj.run()
    out = capsys.readouterr().out
    assert "Files installed by" in out
    assert "Total:" in out


def test_run_normal_singular_file_label(tmp_path: Path, capsys) -> None:
    content = "FILE LIST:\n./usr/bin/ffmpeg\n"
    write_pkg_log(tmp_path, PKG_FULL, content)
    obj = make_list_files(tmp_path, ["ffmpeg"])
    obj.utils.is_package_installed.return_value = PKG_FULL
    obj.run()
    out = capsys.readouterr().out
    assert "1 file" in out
    assert "1 files" not in out
