"""Integration tests for release management functionality.

Tests release add/remove commands with real aptly and Docker containers.
"""

import subprocess
import time
from pathlib import Path

import pytest

# Skip all integration tests if not in Docker environment
pytestmark = pytest.mark.integration


def has_aptly() -> bool:
    """Check if aptly is available."""
    try:
        subprocess.run(["aptly", "version"], capture_output=True, check=True, timeout=5)
        return True
    except (
        subprocess.CalledProcessError,
        FileNotFoundError,
        subprocess.TimeoutExpired,
    ):
        return False


def has_fpm() -> bool:
    """Check if fpm is available."""
    try:
        subprocess.run(["fpm", "--version"], capture_output=True, check=True, timeout=5)
        return True
    except (
        subprocess.CalledProcessError,
        FileNotFoundError,
        subprocess.TimeoutExpired,
    ):
        return False


# Skip if aptly or fpm not available
pytestmark = [
    pytest.mark.integration,
    pytest.mark.skipif(not has_aptly(), reason="aptly not available"),
    pytest.mark.skipif(not has_fpm(), reason="fpm not available"),
]


@pytest.fixture
def unique_codename():
    """Generate unique codename for test isolation."""
    return f"testcodename{int(time.time() * 1000000) % 1000000}"


@pytest.fixture(scope="module")
def test_packages(tmp_path_factory):
    """Create test packages for different releases."""
    packages_dir = tmp_path_factory.mktemp("release_packages")

    def create_package(name, version, arch, codename):
        tmp_dir = tmp_path_factory.mktemp(f"pkg-{name}-{version}-{codename}")
        content_dir = tmp_dir / "etc" / name
        content_dir.mkdir(parents=True)

        # Create file with content specific to release
        (content_dir / "release_info").write_text(
            f"Release: {codename}\nPackage: {name}\nVersion: {version}\n"
        )

        output = packages_dir / f"{name}_{version}_{arch}_{codename}.deb"

        subprocess.run(
            [
                "fpm",
                "-s",
                "dir",
                "-t",
                "deb",
                "-n",
                name,
                "-v",
                version,
                "-a",
                arch,
                "--description",
                f"Test package for {codename} release",
                "-C",
                str(tmp_dir),
                "--package",
                str(output),
                "etc",
            ],
            check=True,
            capture_output=True,
        )

        return str(output)

    # Create packages for different releases
    packages = {
        "trixie": {
            "tools": create_package("jethome-tools-test", "1.0", "amd64", "trixie"),
            "bsp": create_package("jethome-bsp-test", "1.0", "amd64", "trixie"),
        },
        "oracular": {
            "tools": create_package("jethome-tools-test", "1.0", "amd64", "oracular"),
            "bsp": create_package("jethome-bsp-test", "1.0", "amd64", "oracular"),
        },
    }

    return packages


@pytest.fixture(scope="module")
def config_file(tmp_path_factory):
    """Create test configuration for release tests."""
    config_dir = tmp_path_factory.mktemp("release_config")
    config_file = config_dir / "config.yaml"

    aptly_root = tmp_path_factory.mktemp("release_aptly")
    repo_root = tmp_path_factory.mktemp("release_repo")

    # Get GPG key ID
    result = subprocess.run(
        ["gpg", "--list-secret-keys", "--keyid-format", "LONG"],
        capture_output=True,
        text=True,
    )
    gpg_key_id = "TEST_KEY"
    for line in result.stdout.split("\n"):
        if "sec" in line:
            parts = line.split()
            if len(parts) > 1 and "/" in parts[1]:
                gpg_key_id = parts[1].split("/")[1]
                break

    config_file.write_text(
        f"""
aptly:
  root_base: {aptly_root}
  publish_base: {repo_root}

gpg:
  key_id: {gpg_key_id}
  use_agent: true

repositories:
  components: [jethome-tools, jethome-bsp, jethome-armbian]
  architectures: [amd64, arm64]
  auto_create: true
  dual_format:
    enabled: true
    method: symlink
    auto_symlink: true

advanced:
  max_snapshots: 10
  snapshot_format: "{{component}}-{{codename}}-%Y%m%d-%H%M%S%f"
"""
    )

    return str(config_file)


class TestReleaseAdd:
    """Test release add functionality."""

    def test_add_release_default_components(self, config_file, unique_codename):
        """Test adding release with default components."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Add release with default components
        result = release_mgr.add_release(unique_codename)

        # Should create 3 default components
        assert result["created"] == 3
        assert result["failed"] == 0
        assert "jethome-tools" in result["components"]
        assert f"jethome-{unique_codename}" in result["components"]
        assert "jethome-armbian" in result["components"]

        # Verify repos exist
        assert aptly.repo_exists(unique_codename, "jethome-tools")
        assert aptly.repo_exists(unique_codename, f"jethome-{unique_codename}")
        assert aptly.repo_exists(unique_codename, "jethome-armbian")

    def test_add_release_custom_components(self, config_file, unique_codename):
        """Test adding release with custom components."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Add release with custom components
        custom_components = ["jethome-custom1", "jethome-custom2"]
        result = release_mgr.add_release(unique_codename, components=custom_components)

        assert result["created"] == 2
        assert result["failed"] == 0
        assert result["components"] == custom_components

        # Verify repos exist
        for comp in custom_components:
            assert aptly.repo_exists(unique_codename, comp)

    def test_add_release_creates_symlinks(self, config_file, unique_codename):
        """Test that adding release creates dual format symlinks."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Add release
        release_mgr.add_release(unique_codename, skip_symlinks=False)

        # Note: Symlinks are created by _fix_symlinks but need published repos
        # This is tested in CLI integration tests

    def test_add_release_skip_symlinks(self, config_file, unique_codename):
        """Test adding release with skip_symlinks."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Add release with skip_symlinks
        result = release_mgr.add_release(unique_codename, skip_symlinks=True)

        assert result["created"] == 3
        # No error should occur even if symlinks skipped


class TestReleaseRemove:
    """Test release remove functionality."""

    def test_remove_release_with_backup(self, config_file, unique_codename, tmp_path):
        """Test removing release with backup."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # First add a release
        release_mgr.add_release(unique_codename, components=["jethome-test"])

        # Verify it exists
        assert aptly.repo_exists(unique_codename, "jethome-test")

        # Remove with backup
        backup_dir = str(tmp_path / "backups")
        result = release_mgr.remove_release(
            unique_codename, backup=True, force=True, backup_dir=backup_dir
        )

        assert result["deleted"] >= 1
        assert result["backup_file"] is not None
        assert Path(result["backup_file"]).exists()

        # Verify repo removed
        assert not aptly.repo_exists(unique_codename, "jethome-test")

    def test_remove_release_without_backup(self, config_file, unique_codename):
        """Test removing release without backup."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Add release
        release_mgr.add_release(unique_codename, components=["jethome-test"])

        # Remove without backup
        result = release_mgr.remove_release(unique_codename, backup=False, force=True)

        assert result["deleted"] >= 1
        assert result["backup_file"] is None

    def test_remove_nonexistent_release(self, config_file):
        """Test removing non-existent release."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # Try to remove non-existent release
        result = release_mgr.remove_release(
            "nonexistent-codename", backup=False, force=True
        )

        # Should not fail, just report 0 deleted
        assert result["deleted"] == 0


class TestReleaseLifecycle:
    """Test complete release lifecycle."""

    def test_full_release_lifecycle(
        self, config_file, test_packages, unique_codename, tmp_path
    ):
        """Test complete lifecycle: add -> use -> remove."""
        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config
        from debrepomanager.release import ReleaseManager

        config = Config(config_file)
        aptly = AptlyManager(config)
        release_mgr = ReleaseManager(config, aptly)

        # 1. Add release
        result = release_mgr.add_release(
            unique_codename, components=["jethome-tools-test", "jethome-bsp-test"]
        )
        assert result["created"] == 2

        # 2. Add packages
        # Note: Using trixie packages as template
        pkg_tools = test_packages["trixie"]["tools"]
        pkg_bsp = test_packages["trixie"]["bsp"]

        aptly.add_packages(unique_codename, "jethome-tools-test", [pkg_tools])
        aptly.add_packages(unique_codename, "jethome-bsp-test", [pkg_bsp])

        # 3. Verify packages added
        tools_pkgs = aptly.list_packages(unique_codename, "jethome-tools-test")
        bsp_pkgs = aptly.list_packages(unique_codename, "jethome-bsp-test")

        assert len(tools_pkgs) > 0
        assert len(bsp_pkgs) > 0

        # 4. Remove release
        backup_dir = str(tmp_path / "lifecycle_backup")
        result = release_mgr.remove_release(
            unique_codename, backup=True, force=True, backup_dir=backup_dir
        )

        assert result["deleted"] == 2
        assert result["backup_file"] is not None

        # 5. Verify removal
        assert not aptly.repo_exists(unique_codename, "jethome-tools-test")
        assert not aptly.repo_exists(unique_codename, "jethome-bsp-test")


class TestEnvironmentIsolation:
    """Test environment isolation (stable/beta/test)."""

    def test_environment_prefix_isolation(self, config_file, unique_codename, tmp_path):
        """Test that different environments use different publish prefixes."""
        import os

        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config

        # Create different component names for stable and beta to avoid conflicts
        # (same aptly root, different repos)
        # Stable (no prefix)
        os.environ["REPOMANAGER_PUBLISH_PREFIX"] = ""
        config_stable = Config(config_file)
        aptly_stable = AptlyManager(config_stable)
        aptly_stable.create_repo(unique_codename, "jethome-test-stable", force=True)

        # Beta (beta prefix)
        os.environ["REPOMANAGER_PUBLISH_PREFIX"] = "beta"
        config_beta = Config(config_file)
        aptly_beta = AptlyManager(config_beta)
        aptly_beta.create_repo(unique_codename, "jethome-test-beta", force=True)

        # Both should exist
        assert aptly_stable.repo_exists(unique_codename, "jethome-test-stable")
        assert aptly_beta.repo_exists(unique_codename, "jethome-test-beta")

        # Clean up environment
        del os.environ["REPOMANAGER_PUBLISH_PREFIX"]

    def test_add_packages_with_environment(
        self, config_file, test_packages, unique_codename
    ):
        """Test adding packages with environment isolation."""
        import os

        from debrepomanager.aptly import AptlyManager
        from debrepomanager.config import Config

        # Setup for stable
        os.environ["REPOMANAGER_PUBLISH_PREFIX"] = ""
        config_stable = Config(config_file)
        aptly_stable = AptlyManager(config_stable)

        # Create repo and add package to stable
        aptly_stable.create_repo(unique_codename, "jethome-tools-test", force=True)
        pkg_file = test_packages["trixie"]["tools"]
        aptly_stable.add_packages(unique_codename, "jethome-tools-test", [pkg_file])

        # Verify package in stable
        pkgs = aptly_stable.list_packages(unique_codename, "jethome-tools-test")
        assert len(pkgs) > 0
        assert any("jethome-tools-test" in p for p in pkgs)

        # Setup for beta
        os.environ["REPOMANAGER_PUBLISH_PREFIX"] = "beta"
        config_beta = Config(config_file)
        aptly_beta = AptlyManager(config_beta)

        # Create repo in beta
        aptly_beta.create_repo(unique_codename, "jethome-tools-test", force=True)

        # Beta should be empty initially (different from stable)
        # Could check: aptly_beta.list_packages(unique_codename, "jethome-tools-test")

        # Clean up
        del os.environ["REPOMANAGER_PUBLISH_PREFIX"]
