#!/usr/bin/env python3
"""
Test cross-architecture building for deb-bootc-image-builder.

This module tests cross-architecture image building, including:
- Cross-arch manifest validation
- Multi-architecture package handling
- Cross-arch image generation
"""

import pytest
import os
import tempfile
import shutil
import json
from unittest.mock import Mock, patch
import logging

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class TestCrossArchitectureBuilding:
    """Test cases for cross-architecture building functionality."""

    def test_cross_arch_manifest_validation(self, work_dir):
        """Test cross-architecture manifest validation."""
        # Create a test cross-arch manifest
        manifest = {
            "pipeline": {
                "build": {
                    "name": "org.osbuild.debian-filesystem",
                    "options": {
                        "rootfs_type": "ext4",
                        "ostree_integration": True
                    }
                },
                "stages": [
                    {
                        "name": "org.osbuild.apt",
                        "options": {
                            "packages": ["linux-image-amd64", "systemd"],
                            "release": "trixie",
                            "arch": "amd64"
                        }
                    }
                ]
            },
            "target_architectures": ["amd64", "arm64"]
        }
        
        # Validate manifest structure
        assert "pipeline" in manifest
        assert "target_architectures" in manifest
        
        # Validate target architectures
        target_archs = manifest["target_architectures"]
        assert "amd64" in target_archs
        assert "arm64" in target_archs
        assert len(target_archs) == 2

    def test_multi_arch_package_handling(self, work_dir):
        """Test multi-architecture package handling."""
        # Test package lists for different architectures
        amd64_packages = ["linux-image-amd64", "grub-efi-amd64"]
        arm64_packages = ["linux-image-arm64", "grub-efi-arm64"]
        
        # Validate package architecture specificity
        for pkg in amd64_packages:
            assert "amd64" in pkg, f"Package {pkg} should be amd64 specific"
        
        for pkg in arm64_packages:
            assert "arm64" in pkg, f"Package {pkg} should be arm64 specific"
        
        # Test package installation for different architectures
        amd64_result = self._install_arch_packages(amd64_packages, "amd64", work_dir)
        arm64_result = self._install_arch_packages(arm64_packages, "arm64", work_dir)
        
        assert amd64_result is True
        assert arm64_result is True

    def test_cross_arch_filesystem_creation(self, work_dir):
        """Test cross-architecture filesystem creation."""
        # Test filesystem structure for different architectures
        for arch in ["amd64", "arm64"]:
            fs_structure = self._create_arch_filesystem(work_dir, arch)
            
            expected_dirs = ["/etc", "/var", "/home", "/boot", "/usr"]
            for expected_dir in expected_dirs:
                full_path = os.path.join(work_dir, arch, expected_dir.lstrip("/"))
                assert os.path.exists(full_path), f"Directory {expected_dir} not created for {arch}"
            
            # Test architecture-specific paths
            arch_specific_path = os.path.join(work_dir, arch, "usr", "lib", arch)
            assert os.path.exists(arch_specific_path), f"Architecture-specific path not created for {arch}"

    def test_cross_arch_bootloader_configuration(self, work_dir):
        """Test cross-architecture bootloader configuration."""
        # Test GRUB configuration for different architectures
        for arch in ["amd64", "arm64"]:
            grub_config = self._configure_arch_grub(work_dir, arch)
            
            assert "GRUB_DEFAULT" in grub_config
            assert "GRUB_TIMEOUT" in grub_config
            assert "GRUB_CMDLINE_LINUX" in grub_config
            
            # Test architecture-specific boot options
            if arch == "amd64":
                assert "efi" in grub_config["GRUB_CMDLINE_LINUX"]
            elif arch == "arm64":
                assert "arm64" in grub_config["GRUB_CMDLINE_LINUX"]

    def test_cross_arch_image_generation(self, work_dir):
        """Test cross-architecture image generation."""
        # Test image generation for different architectures
        for arch in ["amd64", "arm64"]:
            image_result = self._generate_arch_image(work_dir, arch)
            
            assert image_result["status"] == "success"
            assert image_result["architecture"] == arch
            assert "image_path" in image_result
            assert os.path.exists(image_result["image_path"])
            
            # Test image properties
            image_props = self._get_image_properties(image_result["image_path"])
            assert image_props["architecture"] == arch
            assert image_props["size"] > 0

    def test_cross_arch_dependency_resolution(self, work_dir):
        """Test cross-architecture dependency resolution."""
        # Test dependency resolution for different architectures
        for arch in ["amd64", "arm64"]:
            deps = self._resolve_arch_dependencies(arch, work_dir)
            
            assert "packages" in deps
            assert "repositories" in deps
            
            # Validate architecture-specific dependencies
            packages = deps["packages"]
            for pkg in packages:
                if arch in pkg:
                    assert pkg.endswith(arch), f"Package {pkg} should end with {arch}"

    def _install_arch_packages(self, packages, arch, work_dir):
        """Mock architecture-specific package installation."""
        logger.info(f"Installing {arch} packages: {packages}")
        return True

    def _create_arch_filesystem(self, work_dir, arch):
        """Create architecture-specific filesystem structure."""
        arch_dir = os.path.join(work_dir, arch)
        dirs = [
            "etc", "var", "home", "boot", "usr",
            "usr/bin", "usr/lib", "usr/sbin",
            f"usr/lib/{arch}"
        ]
        
        for dir_path in dirs:
            full_path = os.path.join(arch_dir, dir_path)
            os.makedirs(full_path, exist_ok=True)
        
        # Create /home -> /var/home symlink
        var_home = os.path.join(arch_dir, "var", "home")
        os.makedirs(var_home, exist_ok=True)
        home_link = os.path.join(arch_dir, "home")
        if os.path.exists(home_link):
            os.remove(home_link)
        os.symlink(var_home, home_link)
        
        return {"status": "created", "architecture": arch, "directories": dirs}

    def _configure_arch_grub(self, work_dir, arch):
        """Configure GRUB for specific architecture."""
        arch_dir = os.path.join(work_dir, arch)
        
        if arch == "amd64":
            grub_config = {
                "GRUB_DEFAULT": "0",
                "GRUB_TIMEOUT": "5",
                "GRUB_CMDLINE_LINUX": "console=ttyS0,115200n8 console=tty0 efi"
            }
        elif arch == "arm64":
            grub_config = {
                "GRUB_DEFAULT": "0",
                "GRUB_TIMEOUT": "5",
                "GRUB_CMDLINE_LINUX": "console=ttyAMA0,115200 console=tty0 arm64"
            }
        else:
            grub_config = {
                "GRUB_DEFAULT": "0",
                "GRUB_TIMEOUT": "5",
                "GRUB_CMDLINE_LINUX": "console=tty0"
            }
        
        # Write GRUB configuration
        grub_dir = os.path.join(arch_dir, "etc", "default")
        os.makedirs(grub_dir, exist_ok=True)
        
        grub_file = os.path.join(grub_dir, "grub")
        with open(grub_file, 'w') as f:
            for key, value in grub_config.items():
                f.write(f'{key}="{value}"\n')
        
        return grub_config

    def _generate_arch_image(self, work_dir, arch):
        """Mock architecture-specific image generation."""
        arch_dir = os.path.join(work_dir, arch)
        image_path = os.path.join(arch_dir, f"debian-trixie-{arch}.img")
        
        # Create a dummy image file
        with open(image_path, 'wb') as f:
            f.write(f"Debian {arch} image content".encode())
        
        return {
            "status": "success",
            "architecture": arch,
            "image_path": image_path,
            "size": os.path.getsize(image_path)
        }

    def _get_image_properties(self, image_path):
        """Get image properties."""
        return {
            "architecture": image_path.split("-")[-1].replace(".img", ""),
            "size": os.path.getsize(image_path),
            "path": image_path
        }

    def _resolve_arch_dependencies(self, arch, work_dir):
        """Mock architecture-specific dependency resolution."""
        if arch == "amd64":
            packages = ["linux-image-amd64", "grub-efi-amd64", "initramfs-tools"]
            repositories = ["debian", "debian-security"]
        elif arch == "arm64":
            packages = ["linux-image-arm64", "grub-efi-arm64", "initramfs-tools"]
            repositories = ["debian", "debian-security"]
        else:
            packages = ["linux-image-generic", "grub-efi", "initramfs-tools"]
            repositories = ["debian", "debian-security"]
        
        return {
            "packages": packages,
            "repositories": repositories,
            "architecture": arch
        }


if __name__ == "__main__":
    pytest.main([__file__])
