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

This module tests the ISO image building pipeline, including:
- ISO manifest validation
- ISO creation process
- Debian-specific ISO features
"""

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 TestISOBuilding:
    """Test cases for ISO image building functionality."""

    def test_iso_manifest_validation(self, work_dir):
        """Test ISO manifest validation for Debian images."""
        # Create a test ISO 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"
                        }
                    },
                    {
                        "name": "org.osbuild.debian-grub",
                        "options": {
                            "uefi": True,
                            "secure_boot": False
                        }
                    },
                    {
                        "name": "org.osbuild.debian-kernel",
                        "options": {
                            "kernel_package": "linux-image-amd64",
                            "initramfs_tools": True
                        }
                    }
                ]
            }
        }
        
        # Validate manifest structure
        assert "pipeline" in manifest
        assert "build" in manifest["pipeline"]
        assert "stages" in manifest["pipeline"]
        
        # Validate Debian-specific options
        build_stage = manifest["pipeline"]["build"]
        assert build_stage["name"] == "org.osbuild.debian-filesystem"
        assert build_stage["options"]["ostree_integration"] is True
        
        # Validate stages
        stages = manifest["pipeline"]["stages"]
        assert len(stages) >= 3
        
        # Validate APT stage
        apt_stage = next((s for s in stages if s["name"] == "org.osbuild.apt"), None)
        assert apt_stage is not None
        assert apt_stage["options"]["release"] == "trixie"

    def test_debian_iso_package_installation(self, work_dir):
        """Test Debian package installation for ISO builds."""
        # Mock package installation
        with patch('subprocess.run') as mock_run:
            mock_run.return_value.returncode = 0
            
            # Test package installation
            packages = ["linux-image-amd64", "systemd", "ostree", "grub-efi-amd64"]
            result = self._install_iso_packages(packages, work_dir)
            
            assert result is True
            mock_run.assert_called()

    def test_iso_filesystem_creation(self, work_dir):
        """Test ISO filesystem creation."""
        # Test filesystem structure
        fs_structure = self._create_iso_filesystem(work_dir)
        
        expected_dirs = ["/etc", "/var", "/home", "/boot", "/usr", "/media"]
        for expected_dir in expected_dirs:
            full_path = os.path.join(work_dir, expected_dir.lstrip("/"))
            assert os.path.exists(full_path), f"Directory {expected_dir} not created"
        
        # Test ISO-specific directories
        iso_dirs = ["/media/cdrom", "/media/usb"]
        for iso_dir in iso_dirs:
            full_path = os.path.join(work_dir, iso_dir.lstrip("/"))
            assert os.path.exists(full_path), f"ISO directory {iso_dir} not created"

    def test_iso_bootloader_configuration(self, work_dir):
        """Test ISO bootloader configuration."""
        # Test GRUB configuration for ISO
        grub_config = self._configure_iso_grub(work_dir)
        
        assert "GRUB_DEFAULT" in grub_config
        assert "GRUB_TIMEOUT" in grub_config
        assert "GRUB_CMDLINE_LINUX" in grub_config
        
        # Test ISO-specific boot options
        assert "cdrom" in grub_config["GRUB_CMDLINE_LINUX"]
        assert "iso-scan" in grub_config["GRUB_CMDLINE_LINUX"]

    def test_iso_ostree_integration(self, work_dir):
        """Test OSTree integration for ISO builds."""
        # Test OSTree configuration
        ostree_config = self._setup_iso_ostree(work_dir)
        
        assert ostree_config["mode"] == "bare-user-only"
        assert ostree_config["repo"] == "/var/lib/ostree/repo"
        
        # Test ISO-specific OSTree paths
        iso_repo_path = os.path.join(work_dir, "media", "cdrom", "ostree")
        assert os.path.exists(iso_repo_path), "ISO OSTree repository not created"

    def test_iso_creation_process(self, work_dir):
        """Test the complete ISO creation process."""
        # Test ISO build pipeline
        iso_result = self._create_iso_image(work_dir)
        
        assert iso_result["status"] == "success"
        assert "iso_path" in iso_result
        assert os.path.exists(iso_result["iso_path"])
        
        # Test ISO properties
        iso_props = self._get_iso_properties(iso_result["iso_path"])
        assert iso_props["format"] == "iso9660"
        assert iso_props["size"] > 0

    def _install_iso_packages(self, packages, work_dir):
        """Mock ISO package installation."""
        logger.info(f"Installing ISO packages: {packages}")
        return True

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

    def _configure_iso_grub(self, work_dir):
        """Configure GRUB for ISO boot."""
        grub_config = {
            "GRUB_DEFAULT": "0",
            "GRUB_TIMEOUT": "5",
            "GRUB_CMDLINE_LINUX": "console=ttyS0,115200n8 console=tty0 cdrom iso-scan"
        }
        
        # Write GRUB configuration
        grub_dir = os.path.join(work_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 _setup_iso_ostree(self, work_dir):
        """Set up OSTree for ISO builds."""
        ostree_dir = os.path.join(work_dir, "var", "lib", "ostree", "repo")
        os.makedirs(ostree_dir, exist_ok=True)
        
        # Create ISO-specific OSTree repository
        iso_ostree_dir = os.path.join(work_dir, "media", "cdrom", "ostree")
        os.makedirs(iso_ostree_dir, exist_ok=True)
        
        config = {
            "mode": "bare-user-only",
            "repo": "/var/lib/ostree/repo"
        }
        
        # Write OSTree configuration
        config_file = os.path.join(work_dir, "etc", "ostree", "ostree.conf")
        os.makedirs(os.path.dirname(config_file), exist_ok=True)
        
        with open(config_file, 'w') as f:
            f.write("[core]\n")
            f.write(f"mode={config['mode']}\n")
            f.write(f"repo={config['repo']}\n")
        
        return config

    def _create_iso_image(self, work_dir):
        """Mock ISO image creation."""
        # Create a dummy ISO file
        iso_path = os.path.join(work_dir, "debian-trixie.iso")
        with open(iso_path, 'wb') as f:
            f.write(b"ISO9660 dummy content")
        
        return {
            "status": "success",
            "iso_path": iso_path,
            "size": os.path.getsize(iso_path)
        }

    def _get_iso_properties(self, iso_path):
        """Get ISO image properties."""
        return {
            "format": "iso9660",
            "size": os.path.getsize(iso_path),
            "path": iso_path
        }


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