//! Comprehensive tests for Advanced mode enhancements
//!
//! This module contains integration tests for all Advanced mode functionality
//! including GPU acceleration, memory optimization, SIMD acceleration, and
//! real-time performance adaptation.

#![allow(dead_code)]

use crate::advanced_memory_optimization::AdvancedMemoryOptimizer;
use crate::advanced_simd_acceleration::AdvancedSimdAccelerator;
use crate::error::IntegrateResult;
use crate::gpu_advanced_acceleration::AdvancedGPUAccelerator;
use crate::realtime_performance_adaptation::{
    AdaptationStrategy, AdaptationTriggers, OptimizationObjectives, PerformanceConstraints,
    RealTimeAdaptiveOptimizer, TargetMetrics,
};
use scirs2_core::ndarray::{Array1, Array2, ArrayView1};
use std::time::Duration;

/// Test suite for GPU advanced-acceleration functionality
mod gpu_acceleration_tests {
    use super::*;

    #[test]
    pub fn test_advanced_gpu_accelerator_creation() {
        let result = AdvancedGPUAccelerator::<f64>::new();
        // GPU may not be available in test environment, this is acceptable
        match result {
            Ok(_) => println!("GPU acceleration available"),
            Err(e) => {
                println!("GPU acceleration not available: {e}");
                assert!(
                    e.to_string().contains("GPU acceleration not available"),
                    "Should be GPU unavailable error: {e}"
                );
            }
        }
    }

    #[test]
    fn test_advanced_rk4_step_small_system() {
        let accelerator = match AdvancedGPUAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(_) => {
                println!("GPU not available, skipping GPU-specific test");
                return;
            }
        };
        let y = Array1::from_vec(vec![1.0, 0.5, -0.2, 0.8]);
        let t = 0.0;
        let h = 0.01;

        // Simple ODE: dy/dt = -y
        let ode_func =
            |_t: f64, y: &ArrayView1<f64>| -> IntegrateResult<Array1<f64>> { Ok(-y.to_owned()) };

        let result = accelerator.advanced_rk4_step(t, &y.view(), h, ode_func);
        assert!(result.is_ok(), "RK4 step failed: {:?}", result.err());

        let solution = result.expect("Test: integration failed");
        assert_eq!(solution.len(), y.len());

        // Verify solution is reasonable (should decay for negative derivative)
        for (original, computed) in y.iter().zip(solution.iter()) {
            if *original > 0.0 {
                assert!(*computed < *original, "Positive values should decay");
            }
        }
    }

    #[test]
    fn test_advanced_adaptive_step_control() {
        let accelerator = match AdvancedGPUAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(_) => {
                println!("GPU not available, skipping GPU-specific test");
                return;
            }
        };
        let y = Array1::from_vec(vec![1.0, -1.0]);
        let t = 0.0;
        let h = 0.1;
        let rtol = 1e-6;
        let atol = 1e-8;

        let ode_func = |_t: f64, y: &ArrayView1<f64>| -> IntegrateResult<Array1<f64>> {
            Ok(Array1::from_vec(vec![-y[0], y[1]]))
        };

        let result = accelerator.advanced_adaptive_step(t, &y.view(), h, rtol, atol, ode_func);
        assert!(result.is_ok(), "Adaptive step failed: {:?}", result.err());

        let (solution, new_h, accepted) = result.expect("Test: adaptive step failed");
        assert_eq!(solution.len(), y.len());
        assert!(new_h > 0.0, "New step size should be positive");

        if accepted {
            println!("Step accepted with new h = {new_h}");
        } else {
            println!("Step rejected, suggested h = {new_h}");
        }
    }

    #[test]
    fn test_advanced_memory_pool_operations() {
        let accelerator = match AdvancedGPUAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(_) => {
                println!("GPU not available, skipping GPU-specific test");
                return;
            }
        };

        // Test memory pool allocation and deallocation
        // This is tested indirectly through RK4 operations
        let y = Array1::from_vec(vec![1.0; 100]); // Smaller system for faster testing
        let t = 0.0;
        let h = 0.001;

        let ode_func = |_t: f64, y: &ArrayView1<f64>| -> IntegrateResult<Array1<f64>> {
            Ok(-0.1 * y.to_owned())
        };

        // Multiple steps to test memory pool reuse - reduced iterations for faster testing
        let mut current_y = y.clone();
        let mut current_t = t;

        for _ in 0..3 {
            let result = accelerator.advanced_rk4_step(current_t, &current_y.view(), h, ode_func);
            assert!(result.is_ok(), "Memory pool test failed at step");

            current_y = result.expect("Test: step failed");
            current_t += h;
        }

        // Verify memory pool operations completed successfully and solution has correct structure
        // Note: This test focuses on memory pool operations, not numerical accuracy of the RK4 method.
        // The GPU accelerator may be in simulation mode where numerical results are not meaningful.
        assert_eq!(
            current_y.len(),
            y.len(),
            "Solution should maintain same dimension"
        );
        assert!(
            current_y.iter().all(|&x| x.is_finite()),
            "Solution values should be finite"
        );
    }
}

/// Test suite for advanced memory optimization functionality
mod memory_optimization_tests {
    use crate::AdvancedMemoryOptimizer;

    #[test]
    pub fn test_advanced_memory_optimizer_creation() {
        let result = AdvancedMemoryOptimizer::<f64>::new();
        assert!(
            result.is_ok(),
            "Failed to create AdvancedMemoryOptimizer: {:?}",
            result.err()
        );
    }

    #[test]
    fn test_problem_optimization() {
        let optimizer = AdvancedMemoryOptimizer::<f64>::new().expect("Test: operation failed");

        let result = optimizer.optimize_for_problem(1000, "rk4", 100);
        assert!(
            result.is_ok(),
            "Problem optimization failed: {:?}",
            result.err()
        );

        let plan = result.expect("Test: plan creation failed");
        assert!(
            !plan.optimization_applied.is_empty(),
            "Should have applied some optimizations"
        );
    }

    #[test]
    fn test_solution_memory_allocation() {
        let optimizer = AdvancedMemoryOptimizer::<f64>::new().expect("Test: operation failed");

        // Test different memory sizes
        let sizes = [100, 1000, 10000, 100000];

        for &size in &sizes {
            let result = optimizer.allocate_solution_memory(size);
            assert!(
                result.is_ok(),
                "Memory allocation failed for size {}: {:?}",
                size,
                result.err()
            );

            let memory_region = result.expect("Test: memory allocation failed");
            assert_eq!(memory_region.size, size);
            assert!(memory_region.alignment > 0, "Alignment should be positive");
            assert!(
                !memory_region.optimization_applied.is_empty(),
                "Should have optimizations applied"
            );
        }
    }

    #[test]
    fn test_memory_hierarchy_selection() {
        let optimizer = AdvancedMemoryOptimizer::<f64>::new().expect("Test: operation failed");

        // Small data should prefer faster memory tiers
        let small_result = optimizer.allocate_solution_memory(100);
        assert!(small_result.is_ok());

        // Large data should use appropriate memory tier
        let large_result = optimizer.allocate_solution_memory(1000000);
        assert!(large_result.is_ok());

        let small_region = small_result.expect("Test: small integration failed");
        let large_region = large_result.expect("Test: large integration failed");

        // Different sizes should potentially use different memory tiers
        println!("Small region tier: {:?}", small_region.memory_tier);
        println!("Large region tier: {:?}", large_region.memory_tier);
    }
}

/// Test suite for advanced SIMD acceleration functionality
mod simd_acceleration_tests {
    use crate::{AdvancedSimdAccelerator, IntegrateResult};
    use scirs2_core::ndarray::{Array1, Array2, ArrayView1};

    #[test]
    pub fn test_advanced_simd_accelerator_creation() {
        let result = AdvancedSimdAccelerator::<f64>::new();
        assert!(
            result.is_ok(),
            "Failed to create AdvancedSimdAccelerator: {:?}",
            result.err()
        );
    }

    #[test]
    fn test_advanced_vector_add_fma() {
        let accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping test");
                return;
            }
        };

        let a = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
        let b = Array1::from_vec(vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]);
        let c = Array1::from_vec(vec![0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08]);
        let scale = 2.0;

        let result = accelerator.advanced_vector_add_fma(&a.view(), &b.view(), &c.view(), scale);
        assert!(result.is_ok(), "FMA operation failed: {:?}", result.err());

        let computed = result.expect("Test: computation failed");
        assert_eq!(computed.len(), a.len());

        // Verify FMA computation: result = a + b + scale * c
        for i in 0..a.len() {
            let expected = a[i] + b[i] + scale * c[i];
            let diff = (computed[i] - expected).abs();
            assert!(
                diff < 1e-12,
                "FMA result incorrect at index {}: got {}, expected {}",
                i,
                computed[i],
                expected
            );
        }
    }

    #[test]
    fn test_advanced_matrix_vector_multiply() {
        let accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping test");
                return;
            }
        };

        // Create a simple 4x4 matrix
        let matrix = Array2::from_shape_vec(
            (4, 4),
            vec![
                1.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 4.0,
            ],
        )
        .expect("Test: parallel integration failed");

        let vector = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0]);

        let result = accelerator.advanced_matrix_vector_multiply(&matrix, &vector.view());
        assert!(
            result.is_ok(),
            "Matrix-vector multiply failed: {:?}",
            result.err()
        );

        let computed = result.expect("Test: computation failed");
        let expected = Array1::from_vec(vec![1.0, 4.0, 9.0, 16.0]);

        for i in 0..expected.len() {
            let diff = (computed[i] - expected[i]).abs();
            assert!(
                diff < 1e-12,
                "Matrix-vector result incorrect at index {}: got {}, expected {}",
                i,
                computed[i],
                expected[i]
            );
        }
    }

    #[test]
    fn test_advanced_dot_product() {
        let accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping test");
                return;
            }
        };

        let a = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]);
        let b = Array1::from_vec(vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8]);

        let result = accelerator.advanced_dot_product(&a.view(), &b.view());
        assert!(result.is_ok(), "Dot product failed: {:?}", result.err());

        let computed = result.expect("Test: computation failed");
        let expected: f64 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();

        let diff = (computed - expected).abs();
        assert!(
            diff < 1e-12,
            "Dot product result incorrect: got {computed}, expected {expected}"
        );
    }

    #[test]
    fn test_advanced_reduce_sum() {
        let accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping test");
                return;
            }
        };

        let data = Array1::from_vec(vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]);

        let result = accelerator.advanced_reduce_sum(&data.view());
        assert!(result.is_ok(), "Reduce sum failed: {:?}", result.err());

        let computed = result.expect("Test: computation failed");
        let expected: f64 = data.iter().sum();

        let diff = (computed - expected).abs();
        assert!(
            diff < 1e-12,
            "Reduce sum result incorrect: got {computed}, expected {expected}"
        );
    }

    #[test]
    fn test_advanced_rk4_vectorized() {
        let accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping test");
                return;
            }
        };

        let y = Array1::from_vec(vec![1.0, 0.0]); // [position, velocity]
        let t = 0.0;
        let h = 0.01;

        // Harmonic oscillator: y' = [velocity, -position]
        let ode_func = |_t: f64, y: &ArrayView1<f64>| -> IntegrateResult<Array1<f64>> {
            Ok(Array1::from_vec(vec![y[1], -y[0]]))
        };

        let result = accelerator.advanced_rk4_vectorized(t, &y.view(), h, ode_func);
        assert!(result.is_ok(), "Vectorized RK4 failed: {:?}", result.err());

        let solution = result.expect("Test: solution failed");
        assert_eq!(solution.len(), y.len());

        // For small time step, energy should be approximately conserved
        let initial_energy = 0.5 * (y[0] * y[0] + y[1] * y[1]);
        let final_energy = 0.5 * (solution[0] * solution[0] + solution[1] * solution[1]);
        let energy_error: f64 = (final_energy - initial_energy).abs() / initial_energy;

        assert!(
            energy_error < 0.01,
            "Energy conservation error too large: {energy_error}"
        );
    }
}

/// Test suite for real-time performance adaptation functionality
mod performance_adaptation_tests {
    use crate::realtime_performance_adaptation::types::{
        AdaptationTriggers, OptimizationObjectives, PerformanceConstraints, TargetMetrics,
    };
    use crate::{AdaptationStrategy, RealTimeAdaptiveOptimizer};
    use std::time::Duration;

    #[test]
    pub fn test_real_time_adaptive_optimizer_creation() {
        let _optimizer = RealTimeAdaptiveOptimizer::<f64>::new();
        // Test passes if no panic occurs during creation
    }

    #[test]
    fn test_adaptation_strategy_creation() {
        let strategy = AdaptationStrategy {
            target_metrics: TargetMetrics {
                min_throughput: 100.0,
                max_memory_usage: 1024 * 1024 * 1024, // 1GB
                max_execution_time: Duration::from_millis(1000),
                min_accuracy: 1e-6,
            },
            triggers: AdaptationTriggers {
                performance_degradation_threshold: 0.1,
                memory_pressure_threshold: 0.8,
                error_increase_threshold: 10.0,
                timeout_threshold: Duration::from_secs(5),
            },
            objectives: OptimizationObjectives {
                primary_objective: "balanced".to_string(),
                weight_performance: 0.4,
                weight_accuracy: 0.4,
                weight_memory: 0.2,
            },
            constraints: PerformanceConstraints {
                max_memory: 2 * 1024 * 1024 * 1024, // 2GB
                max_execution_time: Duration::from_secs(10),
                min_accuracy: 1e-8,
                power_budget: 300.0, // watts
            },
        };

        let mut optimizer = RealTimeAdaptiveOptimizer::<f64>::new();
        let result = optimizer.start_optimization(strategy);
        assert!(
            result.is_ok(),
            "Failed to start optimization: {:?}",
            result.err()
        );
    }

    #[test]
    fn test_anomaly_detection() {
        let optimizer = RealTimeAdaptiveOptimizer::<f64>::new();

        // Create mock performance metrics
        let metrics = vec![
            crate::realtime_performance_adaptation::PerformanceMetrics::new(
                std::time::Instant::now(),
                Duration::from_millis(10),
                100.0,
                1024 * 1024,
                50.0,
                30.0,
                0.9,
                1000.0,
                1e-10,
                0.95,
            ),
        ];

        let result = optimizer.anomaly_detection_and_recovery(&metrics);
        assert!(
            result.is_ok(),
            "Anomaly detection failed: {:?}",
            result.err()
        );

        let analysis = result.expect("Test: analysis failed");
        assert!(
            !analysis.recovery_executed || analysis.recovery_plan.is_some(),
            "If recovery was executed, there should be a plan"
        );
    }
}

/// Integration tests combining multiple Advanced mode components
mod integration_tests {
    use crate::realtime_performance_adaptation::types::{
        AdaptationTriggers, OptimizationObjectives, PerformanceConstraints, TargetMetrics,
    };
    use crate::{
        AdaptationStrategy, AdvancedGPUAccelerator, AdvancedMemoryOptimizer,
        AdvancedSimdAccelerator, RealTimeAdaptiveOptimizer,
    };
    use scirs2_core::ndarray::Array1;
    use std::time::Duration;

    #[test]
    pub fn test_full_advanced_mode_integration() {
        // Create all Advanced mode components
        let _gpu_accelerator = match AdvancedGPUAccelerator::<f64>::new() {
            Ok(acc) => Some(acc),
            Err(_) => {
                println!("GPU not available, continuing with CPU-only test");
                None
            }
        };
        let memory_optimizer =
            AdvancedMemoryOptimizer::<f64>::new().expect("Test: operation failed");
        let simd_accelerator =
            AdvancedSimdAccelerator::<f64>::new().expect("Test: operation failed");
        let mut adaptive_optimizer = RealTimeAdaptiveOptimizer::<f64>::new();

        // Test problem setup - use smaller size for faster testing
        let problem_size = 10;
        let y = Array1::from_vec((0..problem_size).map(|i| (i as f64) * 0.001).collect());

        // Memory optimization
        let memory_plan = memory_optimizer
            .optimize_for_problem(problem_size, "rk4", 10)
            .expect("Test: operation failed");
        assert!(!memory_plan.optimization_applied.is_empty());

        // SIMD acceleration test
        let simd_result = simd_accelerator
            .advanced_reduce_sum(&y.view())
            .expect("Test: operation failed");
        let expected_sum: f64 = y.iter().sum();
        assert!((simd_result - expected_sum).abs() < 1e-10);

        // Performance monitoring setup
        let strategy = AdaptationStrategy {
            target_metrics: TargetMetrics {
                min_throughput: 50.0,
                max_memory_usage: 2 * 1024 * 1024 * 1024,
                max_execution_time: Duration::from_secs(1),
                min_accuracy: 1e-8,
            },
            triggers: AdaptationTriggers {
                performance_degradation_threshold: 0.2,
                memory_pressure_threshold: 0.9,
                error_increase_threshold: 5.0,
                timeout_threshold: Duration::from_secs(10),
            },
            objectives: OptimizationObjectives {
                primary_objective: "performance".to_string(),
                weight_performance: 0.6,
                weight_accuracy: 0.3,
                weight_memory: 0.1,
            },
            constraints: PerformanceConstraints {
                max_memory: 4 * 1024 * 1024 * 1024,
                max_execution_time: Duration::from_secs(5),
                min_accuracy: 1e-10,
                power_budget: 500.0,
            },
        };

        adaptive_optimizer
            .start_optimization(strategy)
            .expect("Test: operation failed");

        println!("Full Advanced mode integration test completed successfully");
    }

    #[test]
    fn test_performance_comparison() {
        // Verify SIMD-accelerated reduce_sum produces the same result as scalar sum.
        // Timing assertions are intentionally omitted: for small data sizes the
        // SIMD dispatch overhead dominates, making wall-clock comparisons
        // inherently non-deterministic across machines and CI environments.
        // Benchmarks (criterion) are the right tool for performance regression checks.
        let simd_accelerator = match AdvancedSimdAccelerator::<f64>::new() {
            Ok(acc) => acc,
            Err(e) => {
                println!("SIMD accelerator creation failed: {e:?} - skipping performance comparison test");
                return;
            }
        };

        let data = Array1::from_vec((0..100).map(|i| (i as f64) * 0.0001).collect());

        let simd_result = simd_accelerator
            .advanced_reduce_sum(&data.view())
            .expect("Test: operation failed");
        let scalar_result: f64 = data.iter().sum();

        // Correctness check only — SIMD and scalar must agree within floating-point tolerance
        assert!(
            (simd_result - scalar_result).abs() < 1e-10,
            "SIMD reduce_sum result {simd_result} differs from scalar sum {scalar_result}"
        );
    }
}

#[test]
#[allow(dead_code)]
fn test_advanced_mode_comprehensive() {
    // Run only the basic creation tests for comprehensive testing
    gpu_acceleration_tests::test_advanced_gpu_accelerator_creation();
    memory_optimization_tests::test_advanced_memory_optimizer_creation();
    simd_acceleration_tests::test_advanced_simd_accelerator_creation();
    performance_adaptation_tests::test_real_time_adaptive_optimizer_creation();

    // Skip the full integration test in comprehensive mode to avoid long runtime
    // integration_tests::test_full_advanced_mode_integration();

    println!("All Advanced mode tests passed successfully!");
}
