#!/usr/bin/env python3

"""
Test cx_boost_* macros across different environments.
This script validates boost detection in various scenarios with enhanced portability.
"""

import subprocess
import sys
import os
import platform
import tempfile
import shutil
from pathlib import Path

class EnvironmentTester:
    def __init__(self):
        self.results = []
        self.build_dir = None
        self.script_dir = Path(__file__).parent.absolute()
        self.module_path = self.script_dir.parent / "Modules"
        self.cmake_test_script = self.script_dir / "test_cx_boost_macros.cmake"
        self.tests_passed = 0
        self.tests_total = 0
        
    def setup(self):
        """Create temporary build directory."""
        self.build_dir = Path(tempfile.mkdtemp(prefix="cx_boost_env_test_"))
        print(f"Using build directory: {self.build_dir}")
        return True
        
    def cleanup(self):
        """Clean up temporary files."""
        if self.build_dir and self.build_dir.exists():
            shutil.rmtree(self.build_dir)
            
    def run_test(self, test_name, command, env_vars=None, cwd=None):
        """Run a test command and track results."""
        print(f"\n{'='*60}")
        print(f"Testing: {test_name}")
        print(f"{'='*60}")
        
        self.tests_total += 1
        
        try:
            # Prepare environment
            env = os.environ.copy()
            if env_vars:
                env.update(env_vars)
                print(f"Environment variables: {env_vars}")
                
            # Use provided cwd or default to build_dir
            work_dir = cwd if cwd else self.build_dir
            
            print(f"Command: {' '.join(command) if isinstance(command, list) else command}")
            print(f"Working directory: {work_dir}")
            
            # Run the command
            if isinstance(command, str):
                # Handle shell commands
                result = subprocess.run(
                    command,
                    shell=True,
                    cwd=work_dir,
                    env=env,
                    capture_output=True,
                    universal_newlines=True,
                    timeout=300
                )
            else:
                # Handle command lists
                result = subprocess.run(
                    command,
                    cwd=work_dir,
                    env=env,
                    capture_output=True,
                    universal_newlines=True,
                    timeout=300
                )
            
            success = result.returncode == 0
            
            # Show relevant output
            if result.stdout:
                print("\nCommand Output:")
                for line in result.stdout.split('\n'):
                    if any(keyword in line.upper() for keyword in ['BOOST', 'SUCCESS', 'FAILED', 'ERROR']):
                        print(f"  {line}")
                        
            if result.stderr and not success:
                print("\nCommand Errors:")
                for line in result.stderr.split('\n'):
                    if line.strip():
                        print(f"  {line}")
            
            if success:
                print("✅ PASSED")
                self.tests_passed += 1
            else:
                print("❌ FAILED")
                
            self.results.append((test_name, success, result.stdout, result.stderr))
            return success
            
        except subprocess.TimeoutExpired:
            print("❌ FAILED: Test timed out")
            self.results.append((test_name, False, "", "Timeout"))
            return False
        except Exception as e:
            print(f"❌ FAILED: Exception: {e}")
            self.results.append((test_name, False, "", str(e)))
            return False
            
    def test_standard_environment(self):
        """Test standard environment boost detection."""
        command = [
            "cmake",
            f"-DCMAKE_MODULE_PATH={self.module_path}",
            "-P", str(self.cmake_test_script)
        ]
        return self.run_test("Standard Environment", command)
        
    def test_conda_environment(self):
        """Test conda environment if available."""
        # Check if conda is available
        try:
            conda_result = subprocess.run(["conda", "--version"], capture_output=True, universal_newlines=True)
            if conda_result.returncode != 0:
                print("⚠️  Conda not available, skipping conda test")
                return True
        except FileNotFoundError:
            print("⚠️  Conda not available, skipping conda test")
            return True
            
        # Check if base environment exists
        try:
            envs_result = subprocess.run(["conda", "info", "--envs"], capture_output=True, universal_newlines=True)
            if "base" not in envs_result.stdout:
                print("⚠️  Conda base environment not found, skipping")
                return True
        except Exception:
            print("⚠️  Could not check conda environments, skipping")
            return True
            
        # Get conda base path
        try:
            base_result = subprocess.run(["conda", "info", "--base"], capture_output=True, universal_newlines=True)
            conda_base = base_result.stdout.strip()
        except Exception:
            print("⚠️  Could not determine conda base path, skipping")
            return True
            
        # Test with conda environment
        if platform.system() == "Windows":
            # Windows conda activation
            command = f'call "{conda_base}\\Scripts\\activate.bat" base && cmake -DCMAKE_MODULE_PATH={self.module_path} -P {self.cmake_test_script}'
        else:
            # Unix conda activation
            command = f'source "{conda_base}/etc/profile.d/conda.sh" && conda activate base && cmake -DCMAKE_MODULE_PATH={self.module_path} -P {self.cmake_test_script}'
            
        return self.run_test("Conda Environment", command)
        
    def test_custom_boost_installation(self):
        """Test custom boost installation if exists."""
        boost_paths = [
            Path("/usr/local/include/boost"),
            Path("/opt/homebrew/include/boost"),
            Path("C:/boost/include/boost") if platform.system() == "Windows" else None
        ]
        
        boost_paths = [p for p in boost_paths if p and p.exists()]
        
        if not boost_paths:
            print("⚠️  Custom boost installation not found, skipping")
            return True
            
        boost_root = boost_paths[0].parent.parent
        command = [
            "cmake",
            f"-DCMAKE_MODULE_PATH={self.module_path}",
            "-P", str(self.cmake_test_script)
        ]
        
        env_vars = {"BOOST_ROOT": str(boost_root)}
        return self.run_test("Custom Boost Installation", command, env_vars=env_vars)
        
    def test_el8_boost169(self):
        """Test EL8 boost169 if available."""
        boost169_path = Path("/usr/include/boost169")
        if not boost169_path.exists():
            print("⚠️  EL8 boost169 not found, skipping")
            return True
            
        command = [
            "cmake",
            f"-DCMAKE_MODULE_PATH={self.module_path}",
            "-P", str(self.cmake_test_script)
        ]
        
        env_vars = {
            "BOOST_ROOT": "/usr",
            "BOOST_INCLUDEDIR": "/usr/include/boost169",
            "BOOST_LIBRARYDIR": "/usr/lib64/boost169"
        }
        
        return self.run_test("EL8 boost169", command, env_vars=env_vars)
        
    def test_framecpp_swig_integration(self):
        """Test framecpp-swig integration if available."""
        framecpp_test_dir = self.script_dir.parent.parent / "framecpp-swig" / "test"
        if not framecpp_test_dir.exists():
            print("⚠️  framecpp-swig test directory not found, skipping")
            return True
            
        # Create build directory
        build_dir = framecpp_test_dir / "build"
        build_dir.mkdir(exist_ok=True)
        
        # Run cmake and make
        cmake_cmd = ["cmake", ".."]
        make_cmd = ["make" if platform.system() != "Windows" else "cmake", "--build", "."]
        if platform.system() != "Windows":
            make_cmd.extend(["-j4"])
            
        try:
            # Configure
            result1 = subprocess.run(cmake_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=180)
            if result1.returncode != 0:
                print(f"❌ CMake configuration failed: {result1.stderr}")
                return False
                
            # Build
            result2 = subprocess.run(make_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=600)
            success = result2.returncode == 0
            
            if success:
                print("✅ PASSED: framecpp-swig Integration")
                self.tests_passed += 1
            else:
                print(f"❌ FAILED: framecpp-swig Integration: {result2.stderr}")
                
            self.tests_total += 1
            self.results.append(("framecpp-swig Integration", success, result2.stdout, result2.stderr))
            return success
            
        except Exception as e:
            print(f"❌ FAILED: framecpp-swig Integration: {e}")
            self.tests_total += 1
            self.results.append(("framecpp-swig Integration", False, "", str(e)))
            return False
        finally:
            # Cleanup
            if build_dir.exists():
                shutil.rmtree(build_dir, ignore_errors=True)
                
    def test_version_requirements(self):
        """Test version requirements."""
        command = [
            "cmake",
            f"-DCMAKE_MODULE_PATH={self.module_path}",
            "-DBOOST_MIN_VERSION=1.40",
            "-P", str(self.cmake_test_script)
        ]
        return self.run_test("Version Requirements", command)
        
    def test_verbose_output(self):
        """Test verbose output validation."""
        command = [
            "cmake",
            f"-DCMAKE_MODULE_PATH={self.module_path}",
            "-P", str(self.cmake_test_script)
        ]
        
        try:
            result = subprocess.run(
                command,
                cwd=self.build_dir,
                capture_output=True,
                universal_newlines=True,
                timeout=300
            )
            
            # Check if BOOST.*FOUND appears in output
            output_combined = result.stdout + result.stderr
            success = "BOOST" in output_combined.upper() and "FOUND" in output_combined.upper()
            
            self.tests_total += 1
            if success:
                print("✅ PASSED: Verbose Output")
                self.tests_passed += 1
            else:
                print("❌ FAILED: Verbose Output - BOOST FOUND not detected in output")
                
            self.results.append(("Verbose Output", success, result.stdout, result.stderr))
            return success
            
        except Exception as e:
            print(f"❌ FAILED: Verbose Output: {e}")
            self.tests_total += 1
            self.results.append(("Verbose Output", False, "", str(e)))
            return False
            
    def print_summary(self):
        """Print test summary."""
        print(f"\n{'='*60}")
        print("TEST SUMMARY")
        print(f"{'='*60}")
        
        print(f"\nPlatform: {platform.system()} {platform.machine()}")
        print(f"Python: {platform.python_version()}")
        print(f"Module Path: {self.module_path}")
        
        print(f"\nTests passed: {self.tests_passed}/{self.tests_total}")
        
        for test_name, success, _, _ in self.results:
            status = "✅ PASSED" if success else "❌ FAILED"
            print(f"  {test_name:30} | {status}")
        
        if self.tests_passed == self.tests_total:
            print("\n🎉 ALL cx_boost_* MACRO TESTS PASSED!")
            print("The boost detection macros are working correctly across environments.")
            return True
        else:
            failed = self.tests_total - self.tests_passed
            print(f"\n⚠️  {failed} test(s) failed")
            print("Some boost detection scenarios may need attention.")
            return False
            
def main():
    """Main test execution."""
    print("==============================================")
    print("cx_boost_* Macros Environment Testing")
    print("==============================================")
    
    tester = EnvironmentTester()
    
    try:
        # Setup
        if not tester.setup():
            print("❌ Setup failed")
            return False
            
        # Run tests
        print("\nRunning environment tests...")
        
        tester.test_standard_environment()
        tester.test_conda_environment()
        tester.test_custom_boost_installation()
        tester.test_el8_boost169()
        tester.test_framecpp_swig_integration()
        tester.test_version_requirements()
        tester.test_verbose_output()
        
        # Summary
        success = tester.print_summary()
        return success
        
    finally:
        tester.cleanup()
        
if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)