#!/usr/bin/env python3

"""
Master test script for cx_boost_* macros.
Runs all validation tests and provides comprehensive results with enhanced cross-platform portability.
"""

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

class MasterTestRunner:
    def __init__(self):
        self.results = []
        self.script_dir = Path(__file__).parent.absolute()
        self.module_path = self.script_dir.parent / "Modules" 
        self.tests_passed = 0
        self.tests_total = 0
        
    def print_header(self):
        """Print test suite header."""
        print("=" * 60)
        print("LDAS Tools - cx_boost_* Macros Test Suite")
        print("=" * 60)
        
    def show_environment_info(self):
        """Display environment information."""
        print(f"\n{'Environment Information:':=<60}")
        print(f"OS: {platform.system()} {platform.machine()}")
        print(f"Python: {platform.python_version()}")
        
        # CMake version
        try:
            cmake_result = subprocess.run(["cmake", "--version"], capture_output=True, universal_newlines=True)
            if cmake_result.returncode == 0:
                cmake_version = cmake_result.stdout.split('\n')[0]
                print(f"CMake: {cmake_version}")
            else:
                print("CMake: Not available")
        except FileNotFoundError:
            print("CMake: Not found")
            
        # Conda availability
        try:
            conda_result = subprocess.run(["conda", "--version"], capture_output=True, universal_newlines=True)
            if conda_result.returncode == 0:
                print("Conda: Available")
                try:
                    if "CONDA_PREFIX" in os.environ:
                        print(f"  Active environment: {os.environ['CONDA_PREFIX']}")
                except:
                    pass
            else:
                print("Conda: Not available")
        except FileNotFoundError:
            print("Conda: Not available")
            
        # Boost installation check
        print(f"\n{'Boost Installation Check:':=<60}")
        boost_locations = [
            "/usr/include/boost",
            "/usr/local/include/boost", 
            "/opt/homebrew/include/boost",
            "/usr/include/boost169"
        ]
        
        if platform.system() == "Windows":
            boost_locations.extend([
                "C:/boost/include/boost",
                "C:/Program Files/boost/include/boost"
            ])
            
        found_boost = False
        for location in boost_locations:
            if Path(location).exists():
                print(f"Found boost: {location}")
                found_boost = True
                
        if not found_boost:
            print("No standard boost installations found")
            
    def run_python_test(self, test_name, script_path):
        """Run a Python test script."""
        print(f"\n{'='*60}")
        print(f"Running: {test_name}")
        print(f"Script: {script_path}")
        print(f"{'='*60}")
        
        self.tests_total += 1
        
        if not Path(script_path).exists():
            print(f"❌ MISSING: {script_path} not found")
            self.results.append((test_name, False, "", f"Script not found: {script_path}"))
            return False
            
        try:
            result = subprocess.run(
                [sys.executable, str(script_path)],
                capture_output=True,
                universal_newlines=True,
                timeout=600  # 10 minute timeout
            )
            
            success = result.returncode == 0
            
            # Show relevant output
            if result.stdout:
                print("Test Output:")
                for line in result.stdout.split('\n'):
                    if any(keyword in line for keyword in ['PASSED', 'FAILED', 'SUCCESS', 'ERROR', '✅', '❌']):
                        print(f"  {line}")
                        
            if result.stderr and not success:
                print("Test Errors:")
                for line in result.stderr.split('\n')[:10]:  # Limit error output
                    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 run_cmake_test(self, test_name, cmake_file):
        """Run a CMake test script."""
        print(f"\n{'='*60}")
        print(f"Running: {test_name}")
        print(f"CMake file: {cmake_file}")
        print(f"{'='*60}")
        
        self.tests_total += 1
        
        if not Path(cmake_file).exists():
            print(f"❌ MISSING: {cmake_file} not found")
            self.results.append((test_name, False, "", f"CMake file not found: {cmake_file}"))
            return False
            
        # Create temporary build directory
        build_dir = Path(tempfile.mkdtemp(prefix="cx_boost_cmake_test_"))
        
        try:
            command = [
                "cmake",
                f"-DCMAKE_MODULE_PATH={self.module_path}",
                "-P", str(Path(cmake_file).absolute())
            ]
            
            result = subprocess.run(
                command,
                cwd=build_dir,
                capture_output=True,
                universal_newlines=True,
                timeout=300  # 5 minute timeout
            )
            
            success = result.returncode == 0
            
            # Show relevant output
            if result.stdout:
                print("CMake Output:")
                for line in result.stdout.split('\n'):
                    if any(keyword in line for keyword in ['BOOST', 'SUCCESS', 'FAILED', 'ERROR', '✅', '❌']):
                        print(f"  {line}")
                        
            if result.stderr and not success:
                print("CMake Errors:")
                for line in result.stderr.split('\n')[:10]:  # Limit error output
                    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
        finally:
            # Cleanup
            if build_dir.exists():
                shutil.rmtree(build_dir, ignore_errors=True)
                
    def run_integration_test(self):
        """Run integration test with actual project."""
        print(f"\n{'='*60}")
        print("Running: Integration Test")
        print(f"{'='*60}")
        
        self.tests_total += 1
        
        integration_dir = self.script_dir / "integration"
        if not integration_dir.exists():
            print("❌ MISSING: Integration test directory not found")
            self.results.append(("Integration Test", False, "", "Integration directory not found"))
            return False
            
        # Create temporary build directory
        build_dir = Path(tempfile.mkdtemp(prefix="cx_boost_integration_test_"))
        
        try:
            # Copy integration files
            for file in integration_dir.iterdir():
                if file.is_file():
                    shutil.copy2(file, build_dir)
                    
            # Configure
            cmake_cmd = [
                "cmake",
                f"-DCMAKE_MODULE_PATH={self.module_path}",
                "."
            ]
            
            print(f"Configuring: {' '.join(cmake_cmd)}")
            result1 = subprocess.run(cmake_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=180)
            
            if result1.returncode != 0:
                print(f"❌ FAILED: CMake configuration failed")
                if result1.stderr:
                    print("Configuration errors:")
                    for line in result1.stderr.split('\n')[:5]:
                        if line.strip():
                            print(f"  {line}")
                self.results.append(("Integration Test", False, result1.stdout, result1.stderr))
                return False
                
            # Build
            if platform.system() == "Windows":
                build_cmd = ["cmake", "--build", ".", "--config", "Release"]
            else:
                build_cmd = ["make", "boost_test_simple"]
                if multiprocessing.cpu_count() > 1:
                    build_cmd.extend(["-j", str(min(4, multiprocessing.cpu_count()))])
                    
            print(f"Building: {' '.join(build_cmd)}")
            result2 = subprocess.run(build_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=300)
            
            if result2.returncode != 0:
                print(f"❌ FAILED: Build failed")
                if result2.stderr:
                    print("Build errors:")
                    for line in result2.stderr.split('\n')[:5]:
                        if line.strip():
                            print(f"  {line}")
                self.results.append(("Integration Test", False, result2.stdout, result2.stderr))
                return False
                
            # Run the test executable
            if platform.system() == "Windows":
                test_exe = build_dir / "Release" / "boost_test_simple.exe"
                if not test_exe.exists():
                    test_exe = build_dir / "boost_test_simple.exe"
            else:
                test_exe = build_dir / "boost_test_simple"
                
            if not test_exe.exists():
                print("❌ FAILED: Test executable not found")
                self.results.append(("Integration Test", False, "", "Executable not built"))
                return False
                
            print(f"Running: {test_exe}")
            result3 = subprocess.run([str(test_exe)], cwd=build_dir, capture_output=True, universal_newlines=True, timeout=60)
            
            success = result3.returncode == 0
            
            if result3.stdout:
                print("Test Output:")
                for line in result3.stdout.split('\n'):
                    if line.strip():
                        print(f"  {line}")
                        
            if success:
                print("✅ PASSED: Integration Test")
                self.tests_passed += 1
            else:
                print("❌ FAILED: Integration Test")
                if result3.stderr:
                    print("Runtime errors:")
                    for line in result3.stderr.split('\n')[:5]:
                        if line.strip():
                            print(f"  {line}")
                            
            self.results.append(("Integration Test", success, result3.stdout, result3.stderr))
            return success
            
        except Exception as e:
            print(f"❌ FAILED: Integration Test: {e}")
            self.results.append(("Integration Test", False, "", str(e)))
            return False
        finally:
            # Cleanup
            if build_dir.exists():
                shutil.rmtree(build_dir, ignore_errors=True)
                
    def run_framecpp_swig_test(self):
        """Run framecpp-swig build test 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
            
        print(f"\n{'='*60}")
        print("Running: framecpp-swig Build Test")
        print(f"{'='*60}")
        
        self.tests_total += 1
        
        # Create build directory
        build_dir = framecpp_test_dir / "build_cx_boost_test"
        build_dir.mkdir(exist_ok=True)
        
        try:
            # Configure
            cmake_cmd = ["cmake", ".."]
            result1 = subprocess.run(cmake_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=300)
            
            if result1.returncode != 0:
                print("❌ FAILED: framecpp-swig CMake configuration failed")
                self.results.append(("framecpp-swig Build Test", False, result1.stdout, result1.stderr))
                return False
                
            # Build
            if platform.system() == "Windows":
                build_cmd = ["cmake", "--build", ".", "--config", "Release"]
            else:
                build_cmd = ["make"]
                if multiprocessing.cpu_count() > 1:
                    build_cmd.extend(["-j", str(min(4, multiprocessing.cpu_count()))])
                    
            result2 = subprocess.run(build_cmd, cwd=build_dir, capture_output=True, universal_newlines=True, timeout=600)
            
            success = result2.returncode == 0
            
            if success:
                print("✅ PASSED: framecpp-swig Build Test")
                self.tests_passed += 1
            else:
                print("❌ FAILED: framecpp-swig Build Test")
                if result2.stderr:
                    print("Build errors:")
                    for line in result2.stderr.split('\n')[:5]:
                        if line.strip():
                            print(f"  {line}")
                            
            self.results.append(("framecpp-swig Build Test", success, result2.stdout, result2.stderr))
            return success
            
        except Exception as e:
            print(f"❌ FAILED: framecpp-swig Build Test: {e}")
            self.results.append(("framecpp-swig Build Test", False, "", str(e)))
            return False
        finally:
            # Cleanup
            if build_dir.exists():
                shutil.rmtree(build_dir, ignore_errors=True)
                
    def print_final_summary(self):
        """Print final test summary."""
        print(f"\n{'='*60}")
        print("FINAL 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:35} | {status}")
        
        if self.tests_passed == self.tests_total:
            print("\n🎉 ALL cx_boost_* MACRO TESTS PASSED!")
            print("The boost detection macros are working correctly.")
            print("Ready for production use across all tested 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.")
            print("Review the output above for specific failure details.")
            return False
            
def main():
    """Main test execution."""
    runner = MasterTestRunner()
    
    runner.print_header()
    runner.show_environment_info()
    
    print(f"\n{'Running Test Suite:':=<60}")
    
    # Test 1: Direct CMake testing
    cmake_test_file = runner.script_dir / "test_cx_boost_macros.cmake"
    runner.run_cmake_test("Direct CMake Test", cmake_test_file)
    
    # Test 2: Environment testing (Python version)
    env_test_file = runner.script_dir / "test_cx_boost_environments.py"
    runner.run_python_test("Environment Testing", env_test_file)
    
    # Test 3: Cross-platform validation
    validation_test_file = runner.script_dir / "test_cx_boost_validation.py"
    runner.run_python_test("Cross-Platform Validation", validation_test_file)
    
    # Test 4: Integration test
    runner.run_integration_test()
    
    # Test 5: framecpp-swig build test (if available)
    runner.run_framecpp_swig_test()
    
    # Final summary
    success = runner.print_final_summary()
    return success
    
if __name__ == "__main__":
    success = main()
    sys.exit(0 if success else 1)