#!/usr/bin/python3
"""Tests for slpkg.load_data.LoadData."""

import json
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from slpkg.load_data import LoadData


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

REPO_DATA = {
    "ffmpeg": {"version": "6.1", "requires": ["libass", "x264"]},
    "vlc":   {"version": "3.0.20", "requires": ["ffmpeg"]},
}


def make_load_data(tmp_path: Path) -> LoadData:
    """Construct LoadData bypassing __init__ (avoids config_load/Repositories)."""
    obj: LoadData = object.__new__(LoadData)
    obj.cyan = ""
    obj.green = ""
    obj.red = ""
    obj.endc = ""

    repos = MagicMock()
    repos.data_json = "data.json"
    repos.repositories = {}
    obj.repos = repos

    obj.utils = MagicMock()
    obj.utils.ignore_packages.return_value = []  # default: no blacklisted packages

    obj.black = MagicMock()
    obj.black.packages.return_value = []  # default: empty blacklist

    obj.view_process = MagicMock()
    return obj


def write_data_json(repo_path: Path, data: dict) -> Path:
    repo_path.mkdir(parents=True, exist_ok=True)
    f = repo_path / "data.json"
    f.write_text(json.dumps(data), encoding="utf-8")
    return f


# ---------------------------------------------------------------------------
# read_data_file (static)
# ---------------------------------------------------------------------------


def test_read_data_file_returns_parsed_json(tmp_path: Path) -> None:
    f = write_data_json(tmp_path, REPO_DATA)
    result = LoadData.read_data_file(f)
    assert "ffmpeg" in result
    assert result["ffmpeg"]["version"] == "6.1"


def test_read_data_file_missing_returns_empty(tmp_path: Path) -> None:
    result = LoadData.read_data_file(tmp_path / "nonexistent.json")
    assert result == {}


def test_read_data_file_corrupt_json_returns_empty(tmp_path: Path, capsys) -> None:
    bad = tmp_path / "data.json"
    bad.write_text("{not valid json", encoding="utf-8")
    result = LoadData.read_data_file(bad)
    assert result == {}
    assert "Error" in capsys.readouterr().out


# ---------------------------------------------------------------------------
# _error_database
# ---------------------------------------------------------------------------


def test_error_database_raises_systemexit_when_missing(tmp_path: Path, capsys) -> None:
    obj = make_load_data(tmp_path)
    missing = tmp_path / "data.json"
    with pytest.raises(SystemExit) as exc:
        obj._error_database(missing, "sbo")
    assert exc.value.code == 1
    out = capsys.readouterr().out
    assert "sbo" in out
    assert "slpkg update" in out


def test_error_database_no_raise_when_file_exists(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    f = write_data_json(tmp_path, {})
    obj._error_database(f, "sbo")  # must not raise


# ---------------------------------------------------------------------------
# _remove_blacklist_from_a_repo
# ---------------------------------------------------------------------------


def test_remove_blacklist_from_a_repo_removes_package(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    obj.utils.ignore_packages.return_value = ["ffmpeg"]
    data = {
        "ffmpeg": {"version": "6.1", "requires": []},
        "vlc":   {"version": "3.0.20", "requires": ["ffmpeg"]},
    }
    result = obj._remove_blacklist_from_a_repo(data)
    assert "ffmpeg" not in result


def test_remove_blacklist_from_a_repo_removes_from_requires(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    obj.utils.ignore_packages.return_value = ["libass"]
    data = {
        "ffmpeg": {"version": "6.1", "requires": ["libass", "x264"]},
    }
    result = obj._remove_blacklist_from_a_repo(data)
    assert "libass" not in result["ffmpeg"]["requires"]
    assert "x264" in result["ffmpeg"]["requires"]


def test_remove_blacklist_from_a_repo_no_blacklist_unchanged(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    obj.utils.ignore_packages.return_value = []
    data = {"ffmpeg": {"version": "6.1", "requires": ["libass"]}}
    result = obj._remove_blacklist_from_a_repo(data)
    assert "ffmpeg" in result
    assert "libass" in result["ffmpeg"]["requires"]


# ---------------------------------------------------------------------------
# _remove_blacklist_from_all_repos
# ---------------------------------------------------------------------------


def test_remove_blacklist_from_all_repos_removes_package(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    obj.utils.ignore_packages.return_value = ["ffmpeg"]
    data = {
        "sbo": {
            "ffmpeg": {"version": "6.1", "requires": []},
            "vlc":   {"version": "3.0.20", "requires": ["ffmpeg"]},
        }
    }
    result = obj._remove_blacklist_from_all_repos(data)
    assert "ffmpeg" not in result["sbo"]


def test_remove_blacklist_from_all_repos_removes_from_requires(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    obj.utils.ignore_packages.return_value = ["libass"]
    data = {
        "sbo": {
            "ffmpeg": {"version": "6.1", "requires": ["libass", "x264"]},
        }
    }
    result = obj._remove_blacklist_from_all_repos(data)
    assert "libass" not in result["sbo"]["ffmpeg"]["requires"]
    assert "x264" in result["sbo"]["ffmpeg"]["requires"]


# ---------------------------------------------------------------------------
# load — single repository
# ---------------------------------------------------------------------------


def test_load_single_repo_returns_data(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    repo_path = tmp_path / "sbo"
    write_data_json(repo_path, REPO_DATA)
    obj.repos.repositories["sbo"] = {"path": repo_path, "enable": True}

    result = obj.load("sbo", message=False)

    assert "ffmpeg" in result


def test_load_single_repo_no_message_skips_view_process(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    repo_path = tmp_path / "sbo"
    write_data_json(repo_path, REPO_DATA)
    obj.repos.repositories["sbo"] = {"path": repo_path, "enable": True}

    obj.load("sbo", message=False)

    obj.view_process.message.assert_not_called()


def test_load_single_repo_with_message_calls_view_process(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    repo_path = tmp_path / "sbo"
    write_data_json(repo_path, REPO_DATA)
    obj.repos.repositories["sbo"] = {"path": repo_path, "enable": True}

    obj.load("sbo", message=True)

    obj.view_process.message.assert_called_once()
    obj.view_process.done.assert_called_once()


def test_load_applies_blacklist_single_repo(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    repo_path = tmp_path / "sbo"
    write_data_json(repo_path, REPO_DATA)
    obj.repos.repositories["sbo"] = {"path": repo_path, "enable": True}
    obj.black.packages.return_value = ["ffmpeg"]
    obj.utils.ignore_packages.return_value = ["ffmpeg"]

    result = obj.load("sbo", message=False)

    assert "ffmpeg" not in result


# ---------------------------------------------------------------------------
# load — all repositories (*)
# ---------------------------------------------------------------------------


def test_load_all_repos_includes_enabled_only(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    sbo_path = tmp_path / "sbo"
    alien_path = tmp_path / "alien"
    write_data_json(sbo_path, {"ffmpeg": {"version": "6.1", "requires": []}})
    write_data_json(alien_path, {"vlc":   {"version": "3.0.20", "requires": []}})
    obj.repos.repositories = {
        "sbo":   {"path": sbo_path, "enable": True},
        "alien": {"path": alien_path, "enable": False},
    }

    result = obj.load("*", message=False)

    assert "sbo" in result
    assert "alien" not in result


def test_load_all_repos_applies_blacklist(tmp_path: Path) -> None:
    obj = make_load_data(tmp_path)
    sbo_path = tmp_path / "sbo"
    write_data_json(sbo_path, {
        "ffmpeg": {"version": "6.1", "requires": []},
        "vlc":   {"version": "3.0.20", "requires": []},
    })
    obj.repos.repositories = {"sbo": {"path": sbo_path, "enable": True}}
    obj.black.packages.return_value = ["ffmpeg"]
    obj.utils.ignore_packages.return_value = ["ffmpeg"]

    result = obj.load("*", message=False)

    assert "ffmpeg" not in result["sbo"]
    assert "vlc" in result["sbo"]
