//! Multi-thread scaling efficiency

use std::thread;
use std::time::Instant;

use super::super::error::ProfilingError;
use super::workloads::run_prime_sieve;

/// Scaling efficiency result
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ScalingResult {
    pub threads: u32,
    pub scaling_efficiency: f64,
    pub speedup: f64,
    pub ideal_speedup: f64,
}

/// Measure multi-thread scaling efficiency
/// Uses the same workload (prime sieve) for both single and multi-thread measurements
/// to ensure accurate comparison.
pub fn measure_multi_thread_scaling(threads: u32) -> Result<ScalingResult, ProfilingError> {
    // Validate input
    if threads == 0 {
        return Err(ProfilingError::InvalidConfig(
            "Thread count must be greater than 0".to_string(),
        ));
    }

    super::super::logging::log_info(&format!(
        "Measuring multi-thread scaling with {} threads",
        threads
    ));

    let iterations = 1_000_000u64;

    // Measure single-thread baseline using the SAME workload (prime sieve)
    let start = Instant::now();
    let single_thread_ops = run_prime_sieve(iterations);
    let single_duration = start.elapsed();
    let baseline_score = single_thread_ops as f64 / single_duration.as_secs_f64();

    // Measure multi-thread performance
    let iterations_per_thread = iterations / threads as u64;

    let start = Instant::now();
    let handles: Vec<_> = (0..threads)
        .map(|_| thread::spawn(move || run_prime_sieve(iterations_per_thread)))
        .collect();

    let mut total_ops = 0u64;
    for handle in handles {
        match handle.join() {
            Ok(ops) => total_ops += ops,
            Err(e) => {
                super::super::logging::log_error(&format!(
                    "Thread panicked during scaling test: {:?}",
                    e
                ));
                return Err(ProfilingError::Cancelled);
            }
        }
    }

    let duration = start.elapsed();
    let multi_thread_score = total_ops as f64 / duration.as_secs_f64();

    // Speedup = multi-thread performance / single-thread performance
    // (Higher is better - ideally equals thread count)
    let speedup = multi_thread_score / baseline_score;
    let ideal_speedup = threads as f64;

    // Efficiency = actual speedup / ideal speedup
    // (1.0 = 100% efficient scaling)
    let scaling_efficiency = (speedup / ideal_speedup).clamp(0.0, 2.0);

    Ok(ScalingResult {
        threads,
        scaling_efficiency,
        speedup,
        ideal_speedup,
    })
}
