"""Tests for CLI release commands."""

from unittest.mock import Mock, patch

import pytest
from click.testing import CliRunner

from debrepomanager.cli import cli


@pytest.fixture
def runner():
    """Create CLI test runner."""
    return CliRunner()


@pytest.fixture
def mock_config():
    """Mock config."""
    config = Mock()
    config.publish_base = "/test/repo/public"
    config.auto_create_repos = True
    return config


class TestReleaseAddCommand:
    """Tests for release add command."""

    def test_release_add_basic(self, runner, mock_config):
        """Test basic release add command."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager") as mock_aptly_class:
                mock_aptly = Mock()
                mock_aptly.create_repo = Mock()
                mock_aptly_class.return_value = mock_aptly

                with patch("debrepomanager.cli.ReleaseManager") as mock_release_class:
                    mock_release = Mock()
                    mock_release.add_release.return_value = {
                        "codename": "trixie",
                        "created": 3,
                        "failed": 0,
                        "components": [
                            "jethome-tools",
                            "jethome-trixie",
                            "jethome-armbian",
                        ],
                        "failures": [],
                    }
                    mock_release_class.return_value = mock_release

                    result = runner.invoke(cli, ["release", "add", "trixie"])

                    assert result.exit_code == 0
                    assert "Release trixie created" in result.output
                    assert "Repositories created: 3" in result.output

    def test_release_add_custom_components(self, runner, mock_config):
        """Test release add with custom components."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager") as mock_aptly_class:
                mock_aptly_class.return_value = Mock()

                with patch("debrepomanager.cli.ReleaseManager") as mock_release_class:
                    mock_release = Mock()
                    mock_release.add_release.return_value = {
                        "codename": "oracular",
                        "created": 2,
                        "failed": 0,
                        "components": ["jethome-tools", "jethome-desktop"],
                        "failures": [],
                    }
                    mock_release_class.return_value = mock_release

                    result = runner.invoke(
                        cli,
                        [
                            "release",
                            "add",
                            "oracular",
                            "--components",
                            "jethome-tools",
                            "--components",
                            "jethome-desktop",
                        ],
                    )

                    assert result.exit_code == 0
                    mock_release.add_release.assert_called_once_with(
                        codename="oracular",
                        components=["jethome-tools", "jethome-desktop"],
                        skip_symlinks=False,
                    )

    def test_release_add_skip_symlinks(self, runner, mock_config):
        """Test release add with skip symlinks."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager"):
                with patch("debrepomanager.cli.ReleaseManager") as mock_release_class:
                    mock_release = Mock()
                    mock_release.add_release.return_value = {
                        "codename": "trixie",
                        "created": 3,
                        "failed": 0,
                        "components": [],
                        "failures": [],
                    }
                    mock_release_class.return_value = mock_release

                    result = runner.invoke(
                        cli, ["release", "add", "trixie", "--skip-symlinks"]
                    )

                    assert result.exit_code == 0
                    mock_release.add_release.assert_called_once_with(
                        codename="trixie", components=None, skip_symlinks=True
                    )

    def test_release_add_dry_run(self, runner, mock_config):
        """Test release add in dry-run mode."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            result = runner.invoke(cli, ["--dry-run", "release", "add", "trixie"])

            assert result.exit_code == 0
            assert "Dry-run mode" in result.output
            assert "Would create release: trixie" in result.output


class TestReleaseRemoveCommand:
    """Tests for release remove command."""

    def test_release_remove_without_confirm(self, runner, mock_config):
        """Test release remove without confirmation flag."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            result = runner.invoke(cli, ["release", "remove", "bullseye"])

            assert result.exit_code == 1
            assert "requires --confirm" in result.output

    def test_release_remove_with_confirm(self, runner, mock_config):
        """Test release remove with confirmation."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager") as mock_aptly_class:
                mock_aptly = Mock()
                mock_aptly.list_repos.return_value = ["jethome-tools-bullseye"]
                mock_aptly_class.return_value = mock_aptly

                with patch("debrepomanager.cli.ReleaseManager") as mock_release_class:
                    mock_release = Mock()
                    mock_release.remove_release.return_value = {
                        "codename": "bullseye",
                        "deleted": 1,
                        "failed": 0,
                        "backup_file": "/backup/repo-bullseye.tar.gz",
                        "activity": 0,
                        "failures": [],
                    }
                    mock_release_class.return_value = mock_release

                    # Mock click.confirm to always return True
                    with patch("click.confirm", return_value=True):
                        result = runner.invoke(
                            cli,
                            ["release", "remove", "bullseye", "--confirm"],
                        )

                        assert result.exit_code == 0
                        assert "removed successfully" in result.output

    def test_release_remove_no_backup(self, runner, mock_config):
        """Test release remove without backup."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager") as mock_aptly_class:
                mock_aptly = Mock()
                mock_aptly.list_repos.return_value = ["jethome-tools-bullseye"]
                mock_aptly_class.return_value = mock_aptly

                with patch("debrepomanager.cli.ReleaseManager") as mock_release_class:
                    mock_release = Mock()
                    mock_release.remove_release.return_value = {
                        "codename": "bullseye",
                        "deleted": 1,
                        "failed": 0,
                        "backup_file": None,
                        "activity": 0,
                        "failures": [],
                    }
                    mock_release_class.return_value = mock_release

                    # Mock click.confirm to always return True
                    with patch("click.confirm", return_value=True):
                        result = runner.invoke(
                            cli,
                            [
                                "release",
                                "remove",
                                "bullseye",
                                "--no-backup",
                                "--confirm",
                            ],
                        )

                        assert result.exit_code == 0
                        mock_release.remove_release.assert_called_once()
                        call_args = mock_release.remove_release.call_args
                        assert call_args.kwargs["backup"] is False

    def test_release_remove_dry_run(self, runner, mock_config):
        """Test release remove in dry-run mode."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            result = runner.invoke(
                cli, ["--dry-run", "release", "remove", "bullseye", "--confirm"]
            )

            assert result.exit_code == 0
            assert "Dry-run mode" in result.output
            assert "Would remove release: bullseye" in result.output

    def test_release_remove_no_repos(self, runner, mock_config):
        """Test release remove when no repositories exist."""
        with patch("debrepomanager.cli.Config") as mock_config_class:
            mock_config_class.return_value = mock_config

            with patch("debrepomanager.cli.AptlyManager") as mock_aptly_class:
                mock_aptly = Mock()
                mock_aptly.list_repos.return_value = []
                mock_aptly_class.return_value = mock_aptly

                result = runner.invoke(
                    cli, ["release", "remove", "nonexistent", "--confirm"]
                )

                assert result.exit_code == 1
                assert "No repositories found" in result.output
