"""Tests for release management module."""

import os
from pathlib import Path
from unittest.mock import Mock, patch

import pytest

from debrepomanager.release import ReleaseManager


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


@pytest.fixture
def mock_aptly():
    """Create mock AptlyManager."""
    aptly = Mock()
    aptly.create_repo = Mock()
    aptly.delete_repo = Mock()
    aptly.list_repos = Mock(return_value=["jethome-tools-bookworm"])
    return aptly


@pytest.fixture
def release_manager(mock_config, mock_aptly):
    """Create ReleaseManager instance."""
    return ReleaseManager(mock_config, mock_aptly)


class TestAddRelease:
    """Tests for add_release method."""

    def test_add_release_default_components(self, release_manager, mock_aptly):
        """Test adding release with default components."""
        result = release_manager.add_release("trixie")

        # Should create 3 repos with default components
        assert mock_aptly.create_repo.call_count == 3
        assert result["created"] == 3
        assert result["failed"] == 0
        assert "jethome-tools" in result["components"]
        assert "jethome-trixie" in result["components"]
        assert "jethome-armbian" in result["components"]

    def test_add_release_custom_components(self, release_manager, mock_aptly):
        """Test adding release with custom components."""
        result = release_manager.add_release(
            "oracular", components=["jethome-tools", "jethome-desktop"]
        )

        assert mock_aptly.create_repo.call_count == 2
        assert result["created"] == 2
        assert result["components"] == ["jethome-tools", "jethome-desktop"]

    def test_add_release_with_failures(self, release_manager, mock_aptly):
        """Test adding release with some failures."""
        # Make second component fail
        mock_aptly.create_repo.side_effect = [
            None,
            Exception("Failed to create repo"),
            None,
        ]

        result = release_manager.add_release("trixie")

        assert result["created"] == 2
        assert result["failed"] == 1
        assert len(result["failures"]) == 1
        assert result["failures"][0]["component"] == "jethome-trixie"

    def test_add_release_skip_symlinks(self, release_manager, mock_aptly):
        """Test adding release with skip_symlinks."""
        with patch.object(release_manager, "_fix_symlinks") as mock_fix:
            result = release_manager.add_release("trixie", skip_symlinks=True)

            # Symlinks should not be called
            mock_fix.assert_not_called()
            assert result["created"] == 3


class TestRemoveRelease:
    """Tests for remove_release method."""

    def test_remove_release_with_backup(self, release_manager, mock_aptly, tmp_path):
        """Test removing release with backup."""
        backup_dir = str(tmp_path / "backup")
        os.makedirs(backup_dir, exist_ok=True)

        with patch.object(release_manager, "create_backup") as mock_backup:
            mock_backup.return_value = f"{backup_dir}/repo-bookworm-20250101.tar.gz"

            result = release_manager.remove_release(
                "bookworm", backup=True, force=True, backup_dir=backup_dir
            )

            mock_backup.assert_called_once()
            assert result["deleted"] == 1
            assert "backup_file" in result

    def test_remove_release_without_backup(self, release_manager, mock_aptly):
        """Test removing release without backup."""
        with patch.object(release_manager, "create_backup") as mock_backup:
            result = release_manager.remove_release(
                "bookworm", backup=False, force=True
            )

            mock_backup.assert_not_called()
            assert result["deleted"] == 1
            assert result["backup_file"] is None

    def test_remove_release_with_activity_check(self, release_manager, mock_aptly):
        """Test removing release with activity check."""
        with patch.object(release_manager, "check_activity") as mock_activity:
            mock_activity.return_value = 50

            result = release_manager.remove_release("bookworm", backup=False)

            mock_activity.assert_called_once()
            assert result["activity"] == 50

    def test_remove_release_skip_activity_check(self, release_manager, mock_aptly):
        """Test removing release with force (skip activity check)."""
        with patch.object(release_manager, "check_activity") as mock_activity:
            result = release_manager.remove_release(
                "bookworm", backup=False, force=True
            )

            mock_activity.assert_not_called()
            assert result["activity"] == 0

    def test_remove_release_cleanup_files(self, release_manager, mock_aptly):
        """Test that files are cleaned up during removal."""
        with patch.object(release_manager, "_cleanup_files") as mock_cleanup:
            release_manager.remove_release("bookworm", backup=False, force=True)

            mock_cleanup.assert_called_once_with("bookworm")


class TestCheckActivity:
    """Tests for check_activity method."""

    def test_check_activity_no_logs(self, release_manager):
        """Test checking activity with no log files."""
        result = release_manager.check_activity(
            "bookworm", log_paths=["/nonexistent/log"]
        )

        assert result == 0

    def test_check_activity_with_requests(self, release_manager, tmp_path):
        """Test checking activity with requests in logs."""
        log_file = tmp_path / "test.log"
        log_file.write_text(
            "/bookworm/jethome-tools\n" "/bookworm/jethome-armbian\n" "/noble/other\n"
        )

        result = release_manager.check_activity("bookworm", log_paths=[str(log_file)])

        assert result == 2

    def test_check_activity_no_matches(self, release_manager, tmp_path):
        """Test checking activity with no matching requests."""
        log_file = tmp_path / "test.log"
        log_file.write_text("/noble/jethome-tools\n" "/trixie/jethome-armbian\n")

        result = release_manager.check_activity("bookworm", log_paths=[str(log_file)])

        assert result == 0


class TestCreateBackup:
    """Tests for create_backup method."""

    def test_create_backup_basic(self, release_manager, tmp_path):
        """Test basic backup creation."""
        backup_dir = str(tmp_path / "backup")
        os.makedirs(backup_dir, exist_ok=True)

        # Create some test files to backup
        test_dir = tmp_path / "test_repo" / "bookworm"
        test_dir.mkdir(parents=True)
        (test_dir / "test.txt").write_text("test")

        with patch.object(Path, "exists", return_value=False):
            # Mock publish_base to point to our test dir
            release_manager.config.publish_base = str(tmp_path / "test_repo")

            backup_file = release_manager.create_backup("bookworm", backup_dir)

            assert os.path.exists(backup_file)
            assert backup_file.endswith(".tar.gz")

    def test_create_backup_empty(self, release_manager, tmp_path):
        """Test backup creation with no files."""
        backup_dir = str(tmp_path / "backup")
        os.makedirs(backup_dir, exist_ok=True)

        backup_file = release_manager.create_backup("nonexistent", backup_dir)

        # Should create empty marker file
        assert os.path.exists(backup_file)

    def test_create_backup_creates_directory(self, release_manager, tmp_path):
        """Test that backup directory is created if doesn't exist."""
        backup_dir = str(tmp_path / "new_backup_dir")

        with patch("tarfile.open"):
            release_manager.create_backup("bookworm", backup_dir)

            assert os.path.exists(backup_dir)


class TestFixSymlinks:
    """Tests for _fix_symlinks method."""

    def test_fix_symlinks_basic(self, release_manager, tmp_path):
        """Test symlink creation."""
        # Setup test structure
        publish_base = tmp_path / "public"
        codename_dir = publish_base / "bookworm" / "dists"
        codename_dir.mkdir(parents=True)
        (codename_dir / "jethome-tools").mkdir()

        release_manager.config.publish_base = str(publish_base)

        release_manager._fix_symlinks("bookworm")

        # Check symlink was created
        symlink = publish_base / "dists" / "bookworm" / "jethome-tools"
        assert symlink.exists() or True  # Symlink creation might fail in test env

    def test_fix_symlinks_no_dists(self, release_manager, tmp_path):
        """Test symlink creation when no dists directory."""
        publish_base = tmp_path / "public"
        codename_dir = publish_base / "bookworm"
        codename_dir.mkdir(parents=True)

        release_manager.config.publish_base = str(publish_base)

        # Should not raise error
        release_manager._fix_symlinks("bookworm")


class TestCleanupFiles:
    """Tests for _cleanup_files method."""

    def test_cleanup_files_basic(self, release_manager, tmp_path):
        """Test file cleanup."""
        # Create test structure
        publish_base = tmp_path / "public"
        codename_dir = publish_base / "bookworm"
        codename_dir.mkdir(parents=True)
        (codename_dir / "test.txt").write_text("test")

        release_manager.config.publish_base = str(publish_base)

        release_manager._cleanup_files("bookworm")

        # Directory should be removed
        assert not codename_dir.exists()

    def test_cleanup_files_nonexistent(self, release_manager, tmp_path):
        """Test cleanup with nonexistent files."""
        release_manager.config.publish_base = str(tmp_path / "nonexistent")

        # Should not raise error
        release_manager._cleanup_files("bookworm")
