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

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

import pytest
from slpkg.rollback import Rollback


@pytest.fixture
def mock_config():
    """Mock config_load for Rollback."""
    with patch("slpkg.rollback.config_load") as mock:
        mock.history_log_file = Path("/tmp/history.log")
        mock.cyan = ""
        mock.green = ""
        mock.red = ""
        mock.endc = ""
        mock.yellow = ""
        mock.bold = ""
        yield mock


@pytest.fixture
def rollback_inst(mock_config):
    """Fixture for Rollback instance with mocked dependencies."""
    with patch("slpkg.rollback.History"), \
         patch("slpkg.rollback.Utilities"), \
         patch("slpkg.rollback.View"):
        inst = Rollback({"option_quiet": False, "option_yes": True})
        return inst


def test_parse_last_transaction_install(rollback_inst):
    """Test parsing a batch of INSTALL actions from real log format."""
    history_content = (
        "2026-03-04 10:00 | install   | pkg1 | 1.0 | sbo\n"
        "2026-03-04 10:00 | install   | pkg2 | 1.0 | sbo\n"
    )
    with patch("pathlib.Path.is_file", return_value=True), \
         patch("pathlib.Path.read_text", return_value=history_content):
        transaction = rollback_inst._parse_last_transaction()
        assert len(transaction) == 2
        assert transaction[0]["action"] == "INSTALL"
        assert transaction[0]["package"] == "pkg2"


def test_run_rollback_install(rollback_inst):
    """Test rollback of an INSTALL operation (should call RemovePackages)."""
    mock_transaction = [
        {"action": "INSTALL", "package": "pkg1", "repo": "sbo"}
    ]
    rollback_inst._parse_last_transaction = MagicMock(return_value=mock_transaction)
    rollback_inst.utils.split_package.return_value = {"name": "pkg1"}
    
    with patch("slpkg.rollback.RemovePackages") as mock_remove_cls:
        rollback_inst.run()
        mock_remove_cls.assert_called_once()
        mock_remove_cls.return_value.remove.assert_called_once()


def test_run_rollback_build(rollback_inst, capsys):
    """Test rollback of a BUILD operation: prints warning and exits without action."""
    mock_transaction = [
        {"action": "BUILD", "package": "Flask", "version": "3.0.0", "repo": "sbo"},
        {"action": "BUILD", "package": "werkzeug", "version": "3.0.0", "repo": "sbo"},
    ]
    rollback_inst._parse_last_transaction = MagicMock(return_value=mock_transaction)

    with patch("slpkg.rollback.RemovePackages") as mock_remove_cls, \
         patch("slpkg.rollback.LocalInstall") as mock_local_cls:
        rollback_inst.run()
        mock_remove_cls.assert_not_called()
        mock_local_cls.assert_not_called()

    out = capsys.readouterr().out
    assert "BUILD actions cannot be rolled back" in out


def test_run_rollback_remove(rollback_inst):
    """Test rollback of a REMOVE operation (should call LocalInstall)."""
    mock_transaction = [
        {"action": "REMOVE", "package": "pkg1", "version": "1.0", "repo": "sbo"}
    ]
    rollback_inst._parse_last_transaction = MagicMock(return_value=mock_transaction)
    rollback_inst.utils.split_package.return_value = {"name": "pkg1"}
    
    # Mock finding a local file
    rollback_inst._find_local_package_file = MagicMock(return_value=Path("/tmp/pkg1-1.0.txz"))
    
    with patch("slpkg.rollback.LocalInstall") as mock_local_cls:
        rollback_inst.run()
        mock_local_cls.assert_called_once()
        mock_local_cls.return_value.run.assert_called_once()
