#!/usr/bin/env python3
"""
Real-world Kernel Detection Test for Debian bootc-image-builder

This script tests the kernel detection functionality in real Debian environments,
including container environments and actual Debian systems.

Author: Debian bootc-image-builder team
License: Same as original bootc-image-builder
"""

import os
import sys
import subprocess
import tempfile
import json
import glob
import shutil
from typing import Dict, List, Optional, Any
import logging

# Add the parent directory to the path to import the kernel stage
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from debian_kernel_stage import DebianKernelStage

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


class RealKernelDetectionTest:
    """
    Test class for real-world kernel detection in Debian environments.
    """
    
    def __init__(self):
        self.test_results = {}
        self.temp_dirs = []
    
    def run_all_tests(self) -> bool:
        """
        Run all kernel detection tests.
        
        Returns:
            bool: True if all tests pass, False otherwise
        """
        logger.info("Starting real-world kernel detection tests")
        
        tests = [
            ("test_container_environment", self.test_container_environment),
            ("test_debian_system", self.test_debian_system),
            ("test_kernel_paths", self.test_kernel_paths),
            ("test_kernel_modules", self.test_kernel_modules),
            ("test_initramfs_tools", self.test_initramfs_tools),
            ("test_ostree_integration", self.test_ostree_integration),
        ]
        
        all_passed = True
        
        for test_name, test_func in tests:
            logger.info(f"Running test: {test_name}")
            try:
                result = test_func()
                self.test_results[test_name] = result
                if result:
                    logger.info(f"✓ {test_name} PASSED")
                else:
                    logger.error(f"✗ {test_name} FAILED")
                    all_passed = False
            except Exception as e:
                logger.error(f"✗ {test_name} FAILED with exception: {e}")
                self.test_results[test_name] = False
                all_passed = False
        
        self.print_summary()
        return all_passed
    
    def test_container_environment(self) -> bool:
        """
        Test kernel detection in a Debian container environment.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing kernel detection in container environment")
        
        try:
            # Create a temporary directory for the test
            test_dir = tempfile.mkdtemp(prefix="kernel_test_")
            self.temp_dirs.append(test_dir)
            
            # Create mock kernel files
            kernel_version = "6.1.0-13-amd64"
            kernel_path = f"{test_dir}/boot/vmlinuz-{kernel_version}"
            modules_path = f"{test_dir}/usr/lib/modules/{kernel_version}"
            
            # Create directories and files
            os.makedirs(os.path.dirname(kernel_path), exist_ok=True)
            os.makedirs(modules_path, exist_ok=True)
            
            # Create mock kernel file
            with open(kernel_path, 'w') as f:
                f.write("mock kernel")
            
            # Create a mock osbuild context
            context = MockOsbuildContext(test_dir)
            
            # Initialize the kernel stage
            options = {
                'kernel_package': 'linux-image-amd64',
                'initramfs_tools': True,
                'ostree_integration': True,
                'modules_autoload': True
            }
            
            kernel_stage = DebianKernelStage(options)
            
            # Test kernel detection
            kernel_info = kernel_stage._detect_kernel(context)
            
            # Validate kernel info
            required_keys = ['kernel_path', 'kernel_version', 'modules_path']
            for key in required_keys:
                if key not in kernel_info:
                    logger.error(f"Missing required key in kernel_info: {key}")
                    return False
            
            logger.info(f"Kernel info: {kernel_info}")
            return True
            
        except Exception as e:
            logger.error(f"Container environment test failed: {e}")
            return False
    
    def test_debian_system(self) -> bool:
        """
        Test kernel detection on the actual Debian system.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing kernel detection on actual Debian system")
        
        try:
            # Check if we're running on a Debian system
            if not os.path.exists('/etc/debian_version'):
                logger.warning("Not running on Debian system, skipping test")
                return True
            
            # Check for kernel files
            kernel_paths = [
                '/boot/vmlinuz-*',
                '/usr/lib/modules/*/vmlinuz',
                '/usr/lib/ostree-boot/vmlinuz'
            ]
            
            found_kernels = []
            for pattern in kernel_paths:
                found_kernels.extend(glob.glob(pattern))
            
            if not found_kernels:
                logger.error("No kernel files found")
                return False
            
            logger.info(f"Found kernel files: {found_kernels}")
            
            # Check for initramfs files
            initramfs_paths = [
                '/boot/initrd.img-*',
                '/usr/lib/modules/*/initrd.img',
                '/usr/lib/ostree-boot/initramfs.img'
            ]
            
            found_initramfs = []
            for pattern in initramfs_paths:
                found_initramfs.extend(glob.glob(pattern))
            
            logger.info(f"Found initramfs files: {found_initramfs}")
            
            # Check for kernel modules
            modules_paths = [
                '/usr/lib/modules/*',
                '/lib/modules/*'
            ]
            
            found_modules = []
            for pattern in modules_paths:
                found_modules.extend(glob.glob(pattern))
            
            logger.info(f"Found module directories: {found_modules}")
            
            return len(found_kernels) > 0
            
        except Exception as e:
            logger.error(f"Debian system test failed: {e}")
            return False
    
    def test_kernel_paths(self) -> bool:
        """
        Test kernel path detection logic.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing kernel path detection logic")
        
        try:
            # Create test directory structure
            test_dir = tempfile.mkdtemp(prefix="kernel_paths_test_")
            self.temp_dirs.append(test_dir)
            
            # Create mock kernel files
            kernel_version = "6.1.0-13-amd64"
            kernel_paths = [
                f"{test_dir}/boot/vmlinuz-{kernel_version}",
                f"{test_dir}/usr/lib/modules/{kernel_version}/vmlinuz",
                f"{test_dir}/usr/lib/ostree-boot/vmlinuz"
            ]
            
            for path in kernel_paths:
                os.makedirs(os.path.dirname(path), exist_ok=True)
                with open(path, 'w') as f:
                    f.write("mock kernel")
            
            # Create mock context
            context = MockOsbuildContext(test_dir)
            
            # Test kernel stage detection
            options = {'kernel_package': 'linux-image-amd64'}
            kernel_stage = DebianKernelStage(options)
            
            kernel_info = kernel_stage._detect_kernel(context)
            
            # Validate detection
            if not kernel_info.get('kernel_path'):
                logger.error("No kernel path detected")
                return False
            
            logger.info(f"Detected kernel: {kernel_info}")
            return True
            
        except Exception as e:
            logger.error(f"Kernel paths test failed: {e}")
            return False
    
    def test_kernel_modules(self) -> bool:
        """
        Test kernel module detection and setup.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing kernel module detection and setup")
        
        try:
            # Create test directory structure
            test_dir = tempfile.mkdtemp(prefix="kernel_modules_test_")
            self.temp_dirs.append(test_dir)
            
            # Create mock kernel modules
            kernel_version = "6.1.0-13-amd64"
            modules_dir = f"{test_dir}/usr/lib/modules/{kernel_version}"
            os.makedirs(modules_dir, exist_ok=True)
            
            # Create mock module files
            mock_modules = [
                "kernel/drivers/net/ethernet/intel/e1000e.ko",
                "kernel/drivers/scsi/sd_mod.ko",
                "kernel/fs/ext4/ext4.ko"
            ]
            
            for module in mock_modules:
                module_path = os.path.join(modules_dir, module)
                os.makedirs(os.path.dirname(module_path), exist_ok=True)
                with open(module_path, 'w') as f:
                    f.write("mock module")
            
            # Create mock context
            context = MockOsbuildContext(test_dir)
            
            # Test kernel stage
            options = {'kernel_package': 'linux-image-amd64'}
            kernel_stage = DebianKernelStage(options)
            
            kernel_info = {
                'kernel_version': kernel_version,
                'modules_path': modules_dir
            }
            
            # Test module setup
            kernel_stage._setup_kernel_modules(context, kernel_info)
            
            # Verify module paths
            if not os.path.exists(modules_dir):
                logger.error("Modules directory not created")
                return False
            
            logger.info(f"Kernel modules setup successful: {modules_dir}")
            return True
            
        except Exception as e:
            logger.error(f"Kernel modules test failed: {e}")
            return False
    
    def test_initramfs_tools(self) -> bool:
        """
        Test initramfs-tools integration.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing initramfs-tools integration")
        
        try:
            # Create test directory structure
            test_dir = tempfile.mkdtemp(prefix="initramfs_test_")
            self.temp_dirs.append(test_dir)
            
            # Create mock context
            context = MockOsbuildContext(test_dir)
            
            # Test kernel stage with initramfs-tools
            options = {
                'kernel_package': 'linux-image-amd64',
                'initramfs_tools': True,
                'ostree_integration': True
            }
            
            kernel_stage = DebianKernelStage(options)
            
            # Create mock kernel info
            kernel_info = {
                'kernel_version': '6.1.0-13-amd64',
                'kernel_path': f'{test_dir}/boot/vmlinuz-6.1.0-13-amd64',
                'modules_path': f'{test_dir}/usr/lib/modules/6.1.0-13-amd64'
            }
            
            # Test initramfs configuration
            kernel_stage._configure_initramfs_tools(context, kernel_info)
            
            # Check if initramfs configuration files were created
            initramfs_config_dir = f"{test_dir}/etc/initramfs-tools"
            if not os.path.exists(initramfs_config_dir):
                logger.error("initramfs-tools configuration directory not created")
                return False
            
            logger.info(f"initramfs-tools configuration successful: {initramfs_config_dir}")
            return True
            
        except Exception as e:
            logger.error(f"initramfs-tools test failed: {e}")
            return False
    
    def test_ostree_integration(self) -> bool:
        """
        Test OSTree integration setup.
        
        Returns:
            bool: True if test passes
        """
        logger.info("Testing OSTree integration setup")
        
        try:
            # Create test directory structure
            test_dir = tempfile.mkdtemp(prefix="ostree_test_")
            self.temp_dirs.append(test_dir)
            
            # Create mock context
            context = MockOsbuildContext(test_dir)
            
            # Test kernel stage with OSTree integration
            options = {
                'kernel_package': 'linux-image-amd64',
                'ostree_integration': True
            }
            
            kernel_stage = DebianKernelStage(options)
            
            # Create mock kernel info
            kernel_info = {
                'kernel_version': '6.1.0-13-amd64',
                'kernel_path': f'{test_dir}/boot/vmlinuz-6.1.0-13-amd64'
            }
            
            # Test OSTree integration setup
            kernel_stage._setup_ostree_integration(context, kernel_info)
            
            # Check if OSTree directories were created
            ostree_boot_dir = f"{test_dir}/usr/lib/ostree-boot"
            if not os.path.exists(ostree_boot_dir):
                logger.error("OSTree boot directory not created")
                return False
            
            logger.info(f"OSTree integration setup successful: {ostree_boot_dir}")
            return True
            
        except Exception as e:
            logger.error(f"OSTree integration test failed: {e}")
            return False
    
    def print_summary(self):
        """Print test summary."""
        logger.info("=" * 50)
        logger.info("KERNEL DETECTION TEST SUMMARY")
        logger.info("=" * 50)
        
        passed = sum(1 for result in self.test_results.values() if result)
        total = len(self.test_results)
        
        for test_name, result in self.test_results.items():
            status = "PASSED" if result else "FAILED"
            logger.info(f"{test_name}: {status}")
        
        logger.info(f"Overall: {passed}/{total} tests passed")
        logger.info("=" * 50)
    
    def cleanup(self):
        """Clean up temporary directories."""
        for temp_dir in self.temp_dirs:
            try:
                shutil.rmtree(temp_dir)
            except Exception as e:
                logger.warning(f"Failed to clean up {temp_dir}: {e}")


class MockOsbuildContext:
    """
    Mock osbuild context for testing.
    """
    
    def __init__(self, root_path: str):
        self.root_path = root_path
        self.root = root_path  # Add the root attribute that osbuild stages expect
    
    def run(self, cmd: List[str], **kwargs) -> subprocess.CompletedProcess:
        """Mock run method that simulates osbuild context execution."""
        logger.info(f"Mock context executing: {' '.join(cmd)}")
        
        # Create a mock CompletedProcess
        result = subprocess.CompletedProcess(
            args=cmd,
            returncode=0,
            stdout=b"mock output",
            stderr=b""
        )
        
        return result


def main():
    """Main function to run the tests."""
    logger.info("Starting real-world kernel detection tests")
    
    test_runner = RealKernelDetectionTest()
    
    try:
        success = test_runner.run_all_tests()
        
        if success:
            logger.info("All kernel detection tests PASSED")
            sys.exit(0)
        else:
            logger.error("Some kernel detection tests FAILED")
            sys.exit(1)
            
    finally:
        test_runner.cleanup()


if __name__ == "__main__":
    main()
