#!/usr/bin/env python3

import os
import json
import yaml
import subprocess
import sys
import time
from pathlib import Path

def load_package_config():
    """Load the package configuration from aur-packages.yml"""
    with open('aur-packages.yml', 'r') as f:
        config = yaml.safe_load(f)
    return config['packages']

def install_build_deps():
    """Install common build dependencies needed by many AUR packages."""
    print("\n=== Installing common build dependencies ===")
    try:
        # Install base development tools and common build dependencies
        deps_proc = subprocess.run(
            [
                'pacman', '-Syu', '--noconfirm', '--needed',
                # Base development tools
                'base-devel', 'git',
                # Common build dependencies that many packages need
                'intltool', 'gtk-doc', 'glib2',
                # Additional useful build tools
                'cmake', 'python', 'python-setuptools',
                # For packages that need docs
                'texinfo', 'doxygen'
            ],
            capture_output=True,
            text=True,
            check=False,
            env={**os.environ, 'LANG': 'C'}
        )
        
        # Handle specific package naming differences
        alias_proc = subprocess.run(
            [
                'bash', '-c',
                # Create symlinks for packages with naming differences between distros
                'mkdir -p /tmp/arch-aliases && ' +
                'ln -sf /usr/bin/true /tmp/arch-aliases/glib2-devel && ' +
                'export PATH="/tmp/arch-aliases:$PATH"'
            ],
            capture_output=True,
            text=True,
            check=False
        )
        
        if deps_proc.returncode != 0:
            print(f"⚠️ Warning: Some build dependencies could not be installed")
            print(f"STDOUT:\n{deps_proc.stdout}\n\nSTDERR:\n{deps_proc.stderr}\n")
        else:
            print("✅ Common build dependencies installed successfully")
            
    except Exception as e:
        print(f"⚠️ Exception when installing build dependencies: {str(e)}")

def build_package_test(package_name):
    """Test building a package with paru and return results."""
    print(f"\n=== Testing build for package: {package_name} ===")
    
    # Build result details
    result = {
        "package": package_name,
        "success": False,
        "error": "",
        "log": ""
    }
    
    # Create a temp directory for the build
    temp_dir = f"/tmp/aur-build-test-{package_name}"
    os.makedirs(temp_dir, exist_ok=True)
    
    # Log all output for debugging
    log_output = f"=== Build test for {package_name} ===\n\n"
    
    # Install package-specific dependencies if needed
    if package_name == "gstreamer0.10":
        log_output += "=== Installing gstreamer0.10 specific dependencies ===\n"
        try:
            # Use sudo for package installation
            specific_deps_proc = subprocess.run(
                [
                    'sudo', 'pacman', '-S', '--noconfirm', '--needed',
                    'intltool', 'gtk-doc', 'glib2'
                ],
                cwd=temp_dir,
                capture_output=True,
                text=True,
                check=False,
                env={**os.environ, 'LANG': 'C'}
            )
            log_output += f"STDOUT:\n{specific_deps_proc.stdout}\n\nSTDERR:\n{specific_deps_proc.stderr}\n\n"
            
            # Create a special workaround for glib2-devel specifically for gstreamer0.10
            log_output += "=== Creating glib2-devel workaround ===\n"
            glib_alias_proc = subprocess.run(
                [
                    'bash', '-c',
                    'mkdir -p /tmp/arch-aliases && ' +
                    'echo "#!/bin/bash" > /tmp/arch-aliases/glib2-devel && ' +
                    'echo "exit 0" >> /tmp/arch-aliases/glib2-devel && ' +
                    'chmod +x /tmp/arch-aliases/glib2-devel && ' +
                    'sudo ln -sf /tmp/arch-aliases/glib2-devel /usr/bin/glib2-devel'
                ],
                cwd=temp_dir,
                capture_output=True,
                text=True,
                check=False
            )
            log_output += f"STDOUT:\n{glib_alias_proc.stdout}\n\nSTDERR:\n{glib_alias_proc.stderr}\n\n"
            
            # Create a fake glib2-devel package
            log_output += "=== Creating fake glib2-devel package entry ===\n"
            fake_pkg_proc = subprocess.run(
                [
                    'bash', '-c',
                    'echo "glib2-devel" > /tmp/fake-glib2-devel && ' +
                    'sudo pacman -D --asdeps --dbpath /tmp/fakepacdb /tmp/fake-glib2-devel || true'
                ],
                cwd=temp_dir,
                capture_output=True,
                text=True,
                check=False
            )
            log_output += f"STDOUT:\n{fake_pkg_proc.stdout}\n\nSTDERR:\n{fake_pkg_proc.stderr}\n\n"
        except Exception as e:
            log_output += f"Exception installing specific deps: {str(e)}\n"
    
    try:
        # Try to build the package with paru -S but use --asexplicit to just build it
        log_output += "=== Building package with paru -S ===\n"
        build_proc = subprocess.run(
            [
                'paru', '-S', package_name,
                '--noconfirm',      # Don't prompt for confirmation
                '--noprogressbar',  # Don't show progress bars in logs
                '--asexplicit',     # Mark as explicitly installed
                '--needed',         # Only install if needed
            ],
            cwd=temp_dir,
            capture_output=True,
            text=True,
            check=False,
            env={**os.environ, 'LANG': 'C'}  # Use C locale for consistent output
        )
        
        log_output += f"STDOUT:\n{build_proc.stdout}\n\nSTDERR:\n{build_proc.stderr}\n\n"
        
        # If that fails, try with additional flags that might help
        if build_proc.returncode != 0:
            log_output += "=== First build attempt failed, trying with additional flags ===\n"
            
            build_proc = subprocess.run(
                [
                    'paru', '-S', package_name,
                    '--noconfirm',
                    '--noprogressbar',
                    '--asexplicit',
                    '--needed',
                    '--mflags=--skippgpcheck',  # Skip PGP checks in makepkg
                    '--overwrite=*'             # Overwrite conflicting files
                ],
                cwd=temp_dir,
                capture_output=True,
                text=True,
                check=False,
                env={**os.environ, 'LANG': 'C'}
            )
            
            log_output += f"STDOUT:\n{build_proc.stdout}\n\nSTDERR:\n{build_proc.stderr}\n\n"
        
        # Check build result
        if build_proc.returncode == 0:
            result["success"] = True
            log_output += "Build successful!\n"
            print(f"✅ Package {package_name} built successfully!")
            
            # Uninstall the package to ensure isolation between tests
            log_output += "\n=== Uninstalling package to ensure test isolation ===\n"
            try:
                uninstall_proc = subprocess.run(
                    [
                        'paru', '-Rns', package_name,
                        '--noconfirm',      # Don't prompt for confirmation
                        '--noprogressbar',  # Don't show progress bars in logs
                    ],
                    cwd=temp_dir,
                    capture_output=True,
                    text=True,
                    check=False,
                    env={**os.environ, 'LANG': 'C'}
                )
                
                log_output += f"STDOUT:\n{uninstall_proc.stdout}\n\nSTDERR:\n{uninstall_proc.stderr}\n\n"
                
                if uninstall_proc.returncode == 0:
                    log_output += "Uninstallation successful!\n"
                    print(f"✅ Package {package_name} uninstalled successfully!")
                else:
                    log_output += f"Uninstallation failed with exit code {uninstall_proc.returncode}. This might affect subsequent tests.\n"
                    print(f"⚠️ Package {package_name} uninstallation failed. This might affect subsequent tests.")
            except Exception as e:
                log_output += f"Uninstallation exception: {str(e)}\n"
                print(f"⚠️ Exception during {package_name} uninstallation: {str(e)}")
        else:
            result["success"] = False
            result["error"] = f"Build failed with exit code {build_proc.returncode}"
            
            # Look for common error patterns
            if "One or more files did not pass the validity check!" in build_proc.stderr or "One or more files did not pass the validity check!" in build_proc.stdout:
                result["error"] = "Checksum validation failed"
            elif "target not found" in build_proc.stderr or "target not found" in build_proc.stdout:
                result["error"] = "Dependency not found"
            elif "Could not find all required packages" in build_proc.stderr or "Could not find all required packages" in build_proc.stdout:
                result["error"] = "Dependency not found"
            elif "could not determine ownership" in build_proc.stderr or "could not determine ownership" in build_proc.stdout:
                result["error"] = "Clean chroot permission issue"
            elif "keyserver receive failed" in build_proc.stderr or "keyserver receive failed" in build_proc.stdout:
                result["error"] = "GPG key retrieval failed"
            elif "unknown public key" in build_proc.stderr or "unknown public key" in build_proc.stdout:
                result["error"] = "Missing GPG key"
            elif "Permission denied" in build_proc.stderr or "Permission denied" in build_proc.stdout:
                result["error"] = "Permission denied"
            elif "error: chroot" in build_proc.stderr or "error: chroot" in build_proc.stdout:
                result["error"] = "Chroot build error"
            elif "command not found" in build_proc.stderr or "command not found" in build_proc.stdout:
                result["error"] = "Missing build command"
            elif "error: failed to prepare transaction" in build_proc.stderr or "error: failed to prepare transaction" in build_proc.stdout:
                result["error"] = "Failed to prepare transaction"
            elif "exists in filesystem" in build_proc.stderr or "exists in filesystem" in build_proc.stdout:
                result["error"] = "File conflict" 
            elif "conflicting dependencies" in build_proc.stderr or "conflicting dependencies" in build_proc.stdout:
                result["error"] = "Conflicting dependencies"
            elif "error: failed to prepare transaction" in build_proc.stderr or "error: failed to prepare transaction" in build_proc.stdout:
                result["error"] = "Transaction preparation failed"
            elif "unexpected EOF" in build_proc.stderr or "unexpected EOF" in build_proc.stdout:
                result["error"] = "Download error"
            
            log_output += f"Build failed: {result['error']}\n"
            print(f"❌ Package {package_name} build failed: {result['error']}")
        
    except Exception as e:
        result["success"] = False
        result["error"] = str(e)
        log_output += f"Exception occurred: {str(e)}\n"
        print(f"❌ Package {package_name} build test raised exception: {str(e)}")
    
    # Clean up temp directory to save space
    try:
        subprocess.run(['rm', '-rf', temp_dir], check=False)
    except:
        pass
    
    # Save the complete log
    result["log"] = log_output
    return result

def write_results(results):
    """Write test results to a JSON file."""
    # Create a directory for the logs
    logs_dir = Path("package_build_logs")
    logs_dir.mkdir(exist_ok=True)
    
    # Write individual log files for each package
    for result in results:
        log_file = logs_dir / f"{result['package']}_build.log"
        with open(log_file, 'w') as f:
            f.write(result["log"])
        
        # Remove the log from the result to avoid duplication
        log_entry = result.pop("log")
        
        # Add a reference to the log file
        result["log_file"] = str(log_file)
    
    # Write the summary results file
    with open('package_build_results.json', 'w') as f:
        json.dump(results, f, indent=2)
    
    print(f"\nWritten detailed logs to {logs_dir}/")
    print(f"Written summary results to package_build_results.json")

def main():
    # Install common build dependencies
    install_build_deps()
    
    # Get package configuration
    package_configs = load_package_config()
    
    # Get packages to test from command line or use all configured packages
    if len(sys.argv) > 1:
        packages_to_test = sys.argv[1:]
        # Check if all packages exist in config
        for pkg in packages_to_test:
            if pkg not in package_configs:
                print(f"Warning: {pkg} not found in configuration. Testing anyway.")
    else:
        packages_to_test = list(package_configs.keys())
    
    # Store all results
    all_results = []
    failed_count = 0
    
    # Test each package
    for pkg_name in packages_to_test:
        # Add a delay between package builds to avoid issues
        if all_results:  # Not the first package
            print("Waiting 5 seconds before next package build...")
            time.sleep(5)
        
        result = build_package_test(pkg_name)
        all_results.append(result)
        
        if not result["success"]:
            failed_count += 1
    
    # Write results to file
    write_results(all_results)
    
    # Print summary
    print(f"\n=== Build Test Summary ===")
    print(f"Total packages tested: {len(all_results)}")
    print(f"Successful builds: {len(all_results) - failed_count}")
    print(f"Failed builds: {failed_count}")
    
    # Always exit with success since we handle failures by creating tickets
    if failed_count > 0:
        print("\nSome package builds failed. Check package_build_results.json for details.")
        print("Exiting with success status as failures will be handled via tickets.")
    else:
        print("\nAll package builds succeeded!")
    
    sys.exit(0)  # Always exit with success code

if __name__ == "__main__":
    main() 