#!/usr/bin/env python3
"""
Test manifest validation and processing for deb-bootc-image-builder.

This module tests manifest handling, including:
- Manifest structure validation
- Stage configuration validation
- Debian-specific manifest processing
"""

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

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


class TestManifestValidation:
    """Test cases for manifest validation."""

    def test_debian_manifest_structure(self, work_dir):
        """Test Debian manifest structure validation."""
        manifest = self._create_debian_manifest()
        
        # Validate top-level structure
        assert "pipeline" in manifest
        assert "build" in manifest["pipeline"]
        assert "stages" in manifest["pipeline"]
        
        # Validate build stage
        build_stage = manifest["pipeline"]["build"]
        assert build_stage["name"] == "org.osbuild.debian-filesystem"
        assert "options" in build_stage
        
        # Validate stages
        stages = manifest["pipeline"]["stages"]
        assert len(stages) > 0
        
        # 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 "options" in apt_stage
        assert "packages" in apt_stage["options"]

    def test_debian_package_validation(self, work_dir):
        """Test Debian package validation in manifests."""
        manifest = self._create_debian_manifest()
        
        # Extract packages from APT stage
        apt_stage = next((s for s in manifest["pipeline"]["stages"] 
                         if s["name"] == "org.osbuild.apt"), None)
        packages = apt_stage["options"]["packages"]
        
        # Validate essential Debian packages
        essential_packages = [
            "linux-image-amd64",
            "systemd",
            "ostree"
        ]
        
        for pkg in essential_packages:
            assert pkg in packages, f"Essential package {pkg} missing"
        
        # Validate package format
        for pkg in packages:
            assert isinstance(pkg, str), f"Package {pkg} is not a string"
            assert len(pkg) > 0, f"Empty package name found"

    def test_debian_repository_configuration(self, work_dir):
        """Test Debian repository configuration in manifests."""
        manifest = self._create_debian_manifest()
        
        # Validate repository configuration
        apt_stage = next((s for s in manifest["pipeline"]["stages"] 
                         if s["name"] == "org.osbuild.apt"), None)
        
        options = apt_stage["options"]
        assert "release" in options
        assert "arch" in options
        
        # Validate Debian release
        assert options["release"] == "trixie"
        assert options["arch"] == "amd64"

    def test_ostree_integration_configuration(self, work_dir):
        """Test OSTree integration configuration."""
        manifest = self._create_debian_manifest()
        
        # Validate OSTree integration in filesystem stage
        fs_stage = manifest["pipeline"]["build"]
        options = fs_stage["options"]
        
        assert "ostree_integration" in options
        assert options["ostree_integration"] is True
        
        # Validate home symlink configuration
        assert "home_symlink" in options
        assert options["home_symlink"] is True

    def test_manifest_serialization(self, work_dir):
        """Test manifest serialization to YAML and JSON."""
        manifest = self._create_debian_manifest()
        
        # Test YAML serialization
        yaml_content = yaml.dump(manifest, default_flow_style=False)
        assert "org.osbuild.debian-filesystem" in yaml_content
        assert "org.osbuild.apt" in yaml_content
        
        # Test JSON serialization
        json_content = json.dumps(manifest, indent=2)
        assert "org.osbuild.debian-filesystem" in json_content
        assert "org.osbuild.apt" in json_content
        
        # Test round-trip serialization
        yaml_parsed = yaml.safe_load(yaml_content)
        assert yaml_parsed == manifest
        
        json_parsed = json.loads(json_content)
        assert json_parsed == manifest

    def test_manifest_validation_errors(self, work_dir):
        """Test manifest validation error handling."""
        # Test missing pipeline
        invalid_manifest = {"stages": []}
        with pytest.raises(KeyError):
            _ = invalid_manifest["pipeline"]
        
        # Test missing build stage
        invalid_manifest = {"pipeline": {"stages": []}}
        with pytest.raises(KeyError):
            _ = invalid_manifest["pipeline"]["build"]
        
        # Test missing stages
        invalid_manifest = {"pipeline": {"build": {"name": "test"}}}
        with pytest.raises(KeyError):
            _ = invalid_manifest["pipeline"]["stages"]

    def test_debian_specific_manifest_features(self, work_dir):
        """Test Debian-specific manifest features."""
        manifest = self._create_debian_manifest()
        
        # Test GRUB stage configuration
        grub_stage = next((s for s in manifest["pipeline"]["stages"] 
                          if s["name"] == "org.osbuild.debian-grub"), None)
        
        if grub_stage:
            options = grub_stage["options"]
            assert "uefi" in options
            assert "secure_boot" in options
            assert "timeout" in options
        
        # Test kernel stage configuration
        kernel_stage = next((s for s in manifest["pipeline"]["stages"] 
                           if s["name"] == "org.osbuild.debian-kernel"), None)
        
        if kernel_stage:
            options = kernel_stage["options"]
            assert "kernel_package" in options
            assert "initramfs_tools" in options

    def _create_debian_manifest(self):
        """Create a sample Debian manifest for testing."""
        return {
            "pipeline": {
                "build": {
                    "name": "org.osbuild.debian-filesystem",
                    "options": {
                        "rootfs_type": "ext4",
                        "ostree_integration": True,
                        "home_symlink": True
                    }
                },
                "stages": [
                    {
                        "name": "org.osbuild.apt",
                        "options": {
                            "packages": [
                                "linux-image-amd64",
                                "linux-headers-amd64",
                                "systemd",
                                "systemd-sysv",
                                "dbus",
                                "ostree",
                                "grub-efi-amd64",
                                "initramfs-tools",
                                "util-linux",
                                "parted",
                                "e2fsprogs",
                                "dosfstools",
                                "efibootmgr",
                                "sudo",
                                "network-manager"
                            ],
                            "release": "trixie",
                            "arch": "amd64"
                        }
                    },
                    {
                        "name": "org.osbuild.debian-grub",
                        "options": {
                            "uefi": True,
                            "secure_boot": False,
                            "timeout": 5,
                            "default_entry": 0
                        }
                    },
                    {
                        "name": "org.osbuild.debian-kernel",
                        "options": {
                            "kernel_package": "linux-image-amd64",
                            "initramfs_tools": True,
                            "ostree_integration": True
                        }
                    }
                ]
            }
        }


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