#!/usr/bin/python3
"""Tests for slpkg.blacklist_cmd.BlacklistCmd.view(), add(), remove()."""

from __future__ import annotations

from pathlib import Path
from unittest.mock import MagicMock

import pytest
import tomlkit

from slpkg.blacklist_cmd import BlacklistCmd

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


def make_cmd(packages: list[str], quiet: bool = False) -> BlacklistCmd:
    """Construct BlacklistCmd bypassing __init__ (avoids config_load)."""
    cmd: BlacklistCmd = object.__new__(BlacklistCmd)
    cmd.blacklist_file = Path("/etc/slpkg/blacklist.toml")
    cmd.bold = ""
    cmd.grey = ""
    cmd.cyan = ""
    cmd.green = ""
    cmd.endc = ""
    cmd.quiet = quiet
    cmd.black = MagicMock()
    cmd.black.packages.return_value = packages
    cmd.utils = MagicMock()
    cmd.utils.all_installed.return_value = {}
    return cmd


def make_cmd_with_file(tmp_path: Path, packages: list[str]) -> BlacklistCmd:
    """Construct BlacklistCmd with a real temp blacklist file for add/remove tests."""
    toml_file = tmp_path / "blacklist.toml"
    doc = tomlkit.document()
    arr = tomlkit.array()
    arr.extend(packages)
    doc.add("PACKAGES", arr)
    toml_file.write_text(tomlkit.dumps(doc), encoding="utf-8")

    cmd: BlacklistCmd = object.__new__(BlacklistCmd)
    cmd.blacklist_file = toml_file
    cmd.bold = ""
    cmd.grey = ""
    cmd.cyan = ""
    cmd.green = ""
    cmd.endc = ""
    cmd.quiet = False
    cmd.black = MagicMock()
    cmd.utils = MagicMock()
    return cmd


def read_packages(toml_file: Path) -> list[str]:
    """Read PACKAGES list from a TOML file."""
    return [str(p) for p in tomlkit.parse(toml_file.read_text(encoding="utf-8")).get("PACKAGES", [])]


# ---------------------------------------------------------------------------
# view() — empty blacklist
# ---------------------------------------------------------------------------


def test_view_empty_blacklist_prints_no_packages(capsys: pytest.CaptureFixture) -> None:
    make_cmd([]).view()
    out = capsys.readouterr().out
    assert "No blacklisted packages found." in out


def test_view_empty_blacklist_shows_file_path(capsys: pytest.CaptureFixture) -> None:
    make_cmd([]).view()
    out = capsys.readouterr().out
    assert "/etc/slpkg/blacklist.toml" in out


# ---------------------------------------------------------------------------
# view() — non-empty blacklist
# ---------------------------------------------------------------------------


def test_view_lists_all_packages(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim", "ffmpeg", "python3"])
    cmd.view()
    out = capsys.readouterr().out
    assert "vim" in out
    assert "ffmpeg" in out
    assert "python3" in out


def test_view_packages_sorted(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["zzz", "aaa", "mmm"])
    cmd.view()
    out = capsys.readouterr().out
    assert out.index("aaa") < out.index("mmm") < out.index("zzz")


def test_view_shows_package_name(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim"])
    cmd.view()
    assert "vim" in capsys.readouterr().out


def test_view_no_installed_label(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["nonexistent"])
    cmd.view()
    assert "not installed" not in capsys.readouterr().out


def test_view_shows_entry_name_only(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["google-chrome"])
    cmd.view()
    out = capsys.readouterr().out
    assert "google-chrome" in out
    assert "google-chrome-stable" not in out


def test_view_footer_shows_count(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim", "ffmpeg"])
    cmd.view()
    out = capsys.readouterr().out
    assert "2" in out
    assert "blacklisted" in out


def test_view_footer_singular(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim"])
    cmd.view()
    assert "1 blacklisted package." in capsys.readouterr().out


def test_view_footer_shows_file_path(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim"])
    cmd.view()
    assert "/etc/slpkg/blacklist.toml" in capsys.readouterr().out


# ---------------------------------------------------------------------------
# view() — quiet mode
# ---------------------------------------------------------------------------


def test_view_quiet_prints_only_names(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim", "ffmpeg"], quiet=True)
    cmd.view()
    lines = [ln for ln in capsys.readouterr().out.splitlines() if ln.strip()]
    assert set(lines) == {"vim", "ffmpeg"}


def test_view_quiet_no_header(capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd(["vim"], quiet=True)
    cmd.view()
    assert "Blacklisted" not in capsys.readouterr().out


def test_view_quiet_empty_produces_no_output(capsys: pytest.CaptureFixture) -> None:
    make_cmd([], quiet=True).view()
    assert capsys.readouterr().out == ""


# ---------------------------------------------------------------------------
# add()
# ---------------------------------------------------------------------------


def test_add_new_package(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.add(["vlc"])
    assert read_packages(cmd.blacklist_file) == ["vlc"]


def test_add_multiple_packages(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.add(["vlc", "ffmpeg"])
    assert read_packages(cmd.blacklist_file) == ["vlc", "ffmpeg"]


def test_add_preserves_existing(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vim"])
    cmd.add(["vlc"])
    pkgs = read_packages(cmd.blacklist_file)
    assert "vim" in pkgs
    assert "vlc" in pkgs


def test_add_skips_duplicate(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc"])
    cmd.add(["vlc"])
    assert read_packages(cmd.blacklist_file) == ["vlc"]
    assert "already in blacklist" in capsys.readouterr().out


def test_add_partial_duplicate(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vim"])
    cmd.add(["vim", "ffmpeg"])
    pkgs = read_packages(cmd.blacklist_file)
    assert pkgs.count("vim") == 1
    assert "ffmpeg" in pkgs


def test_add_prints_added_name(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.add(["vlc"])
    assert "vlc" in capsys.readouterr().out


def test_add_prints_count(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.add(["vlc", "ffmpeg"])
    assert "2" in capsys.readouterr().out


def test_add_prints_count_singular(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.add(["vlc"])
    out = capsys.readouterr().out
    assert "1" in out
    assert "package" in out


def test_add_creates_file_if_missing(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.blacklist_file.unlink()
    cmd.add(["vlc"])
    assert read_packages(cmd.blacklist_file) == ["vlc"]


# ---------------------------------------------------------------------------
# remove()
# ---------------------------------------------------------------------------


def test_remove_existing_package(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc", "ffmpeg"])
    cmd.remove(["vlc"])
    assert read_packages(cmd.blacklist_file) == ["ffmpeg"]


def test_remove_multiple_packages(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc", "ffmpeg", "vim"])
    cmd.remove(["vlc", "ffmpeg"])
    assert read_packages(cmd.blacklist_file) == ["vim"]


def test_remove_all_packages(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc"])
    cmd.remove(["vlc"])
    assert read_packages(cmd.blacklist_file) == []


def test_remove_not_found_warns(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vim"])
    cmd.remove(["nonexistent"])
    assert "not in blacklist" in capsys.readouterr().out


def test_remove_not_found_does_not_change_file(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vim"])
    cmd.remove(["nonexistent"])
    assert read_packages(cmd.blacklist_file) == ["vim"]


def test_remove_prints_removed_name(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc"])
    cmd.remove(["vlc"])
    assert "vlc" in capsys.readouterr().out


def test_remove_prints_count(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc", "ffmpeg"])
    cmd.remove(["vlc", "ffmpeg"])
    assert "2" in capsys.readouterr().out


def test_remove_empty_list_clears_all(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc", "ffmpeg", "vim"])
    cmd.remove([])
    assert read_packages(cmd.blacklist_file) == []


def test_remove_empty_list_prints_count(tmp_path: Path, capsys: pytest.CaptureFixture) -> None:
    cmd = make_cmd_with_file(tmp_path, ["vlc", "ffmpeg"])
    cmd.remove([])
    assert "2" in capsys.readouterr().out


def test_remove_empty_list_on_empty_blacklist(tmp_path: Path) -> None:
    cmd = make_cmd_with_file(tmp_path, [])
    cmd.remove([])
    assert read_packages(cmd.blacklist_file) == []
