//! Rhai bindings for CPU profiling functions

use super::super::error::ToRhaiError;
use rhai::{Engine, EvalAltResult};

/// Register CPU profiling module with Rhai engine
pub fn register_cpu_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
    // Register CPUBenchmarkResult type
    engine.register_type_with_name::<super::CPUBenchmarkResult>("CPUBenchmarkResult");
    engine.register_get("single_thread", |result: &mut super::CPUBenchmarkResult| {
        result.single_thread.clone()
    });
    engine.register_get("multi_thread", |result: &mut super::CPUBenchmarkResult| {
        result.multi_thread.clone()
    });
    engine.register_get("scaling", |result: &mut super::CPUBenchmarkResult| {
        result.scaling.clone()
    });
    engine.register_get("cache_misses", |result: &mut super::CPUBenchmarkResult| {
        result.cache_misses.clone()
    });

    engine.register_fn(
        "measure_single_thread_performance",
        || -> Result<super::single::SingleThreadResult, Box<EvalAltResult>> {
            super::single::measure_single_thread_performance().to_rhai_error()
        },
    );

    // Register SingleThreadResult type
    engine.register_type_with_name::<super::single::SingleThreadResult>("SingleThreadResult");
    engine.register_get(
        "integer_score",
        |result: &mut super::single::SingleThreadResult| result.integer_score,
    );
    engine.register_get(
        "float_score",
        |result: &mut super::single::SingleThreadResult| result.float_score,
    );
    engine.register_get(
        "combined_score",
        |result: &mut super::single::SingleThreadResult| result.combined_score,
    );
    engine.register_get(
        "duration",
        |result: &mut super::single::SingleThreadResult| result.duration,
    );

    // Register ScalingResult type
    engine.register_type_with_name::<super::scaling::ScalingResult>("ScalingResult");
    engine.register_get("threads", |result: &mut super::scaling::ScalingResult| {
        result.threads
    });
    engine.register_get(
        "scaling_efficiency",
        |result: &mut super::scaling::ScalingResult| result.scaling_efficiency,
    );
    engine.register_get("speedup", |result: &mut super::scaling::ScalingResult| {
        result.speedup
    });
    engine.register_get(
        "ideal_speedup",
        |result: &mut super::scaling::ScalingResult| result.ideal_speedup,
    );

    engine.register_fn(
        "measure_multi_thread_scaling",
        |threads: i64| -> Result<super::scaling::ScalingResult, Box<EvalAltResult>> {
            super::scaling::measure_multi_thread_scaling(threads as u32).to_rhai_error()
        },
    );

    // Register InstructionResult type
    engine.register_type::<super::workloads::InstructionResult>();
    engine.register_get(
        "integer_ops_per_sec",
        |result: &mut super::workloads::InstructionResult| result.integer_ops_per_sec,
    );
    engine.register_get(
        "float_ops_per_sec",
        |result: &mut super::workloads::InstructionResult| result.float_ops_per_sec,
    );
    engine.register_get(
        "simd_ops_per_sec",
        |result: &mut super::workloads::InstructionResult| result.simd_ops_per_sec,
    );

    engine.register_fn(
        "test_instruction_throughput",
        || -> Result<super::workloads::InstructionResult, Box<EvalAltResult>> {
            super::workloads::test_instruction_throughput().to_rhai_error()
        },
    );

    // Register CacheMissResult type
    engine.register_type::<super::cache::CacheMissResult>();
    engine.register_get(
        "l1_miss_rate",
        |result: &mut super::cache::CacheMissResult| result.l1_miss_rate,
    );
    engine.register_get(
        "l2_miss_rate",
        |result: &mut super::cache::CacheMissResult| result.l2_miss_rate,
    );
    engine.register_get(
        "l3_miss_rate",
        |result: &mut super::cache::CacheMissResult| result.l3_miss_rate,
    );

    engine.register_fn(
        "measure_cache_misses",
        || -> Result<super::cache::CacheMissResult, Box<EvalAltResult>> {
            super::cache::measure_cache_misses().to_rhai_error()
        },
    );

    engine.register_fn(
        "profile_cpu_usage",
        |pid: i64,
         duration_sec: i64|
         -> Result<super::usage::CPUUsageProfile, Box<EvalAltResult>> {
            super::usage::profile_cpu_usage(
                pid as u32,
                std::time::Duration::from_secs(duration_sec as u64),
            )
            .to_rhai_error()
        },
    );

    // Register thermal functions
    engine.register_fn(
        "detect_thermal_state",
        || -> Result<Option<super::ThermalState>, Box<EvalAltResult>> {
            super::throttle::detect_thermal_state().to_rhai_error()
        },
    );

    engine.register_fn(
        "is_thermal_throttling",
        || -> Result<Option<bool>, Box<EvalAltResult>> {
            super::throttle::is_thermal_throttling().to_rhai_error()
        },
    );

    engine.register_fn("is_thermal_detection_supported", || -> bool {
        super::throttle::is_thermal_detection_supported()
    });

    // Register ThermalState type and getters for Option<ThermalState>
    engine.register_type_with_name::<super::ThermalState>("ThermalState");
    engine.register_get("severity", |opt_state: &mut Option<super::ThermalState>| {
        if let Some(ref state) = opt_state.as_ref() {
            state.severity
        } else {
            super::ThermalSeverity::Normal
        }
    });
    engine.register_get(
        "is_throttling",
        |opt_state: &mut Option<super::ThermalState>| {
            if let Some(ref state) = opt_state.as_ref() {
                state.is_throttling
            } else {
                false
            }
        },
    );
    engine.register_get(
        "temperature_celsius",
        |opt_state: &mut Option<super::ThermalState>| {
            if let Some(ref state) = opt_state.as_ref() {
                state.temperature_celsius
            } else {
                None
            }
        },
    );
    engine.register_get("platform", |opt_state: &mut Option<super::ThermalState>| {
        if let Some(ref state) = opt_state.as_ref() {
            state.platform
        } else {
            super::ThermalPlatform::Unknown
        }
    });

    engine.register_fn(
        "run_cpu_benchmark",
        |threads: i64,
         duration_sec: i64|
         -> Result<super::CPUBenchmarkResult, Box<EvalAltResult>> {
            super::profiler::run_cpu_benchmark(
                threads as u32,
                std::time::Duration::from_secs(duration_sec as u64),
            )
            .to_rhai_error()
        },
    );

    // Register parameterized benchmark functions for Rhai scripting
    engine.register_fn(
        "benchmark_cpu",
        || -> Result<super::CPUBenchmarkResult, Box<EvalAltResult>> {
            super::profiler::run_cpu_benchmark(4, std::time::Duration::from_secs(30))
                .to_rhai_error()
        },
    );

    engine.register_fn(
        "benchmark_cpu_threads",
        |threads: i64| -> Result<super::CPUBenchmarkResult, Box<EvalAltResult>> {
            use super::super::config::limits::cpu::*;
            if threads < MIN_THREADS as i64 || threads > MAX_THREADS as i64 {
                return Err(format!(
                    "threads must be between {} and {}",
                    MIN_THREADS, MAX_THREADS
                )
                .into());
            }
            let profiler = super::profiler::CPUProfiler::new();
            profiler
                .run_benchmark(
                    threads as u32,
                    std::time::Duration::from_secs(DEFAULT_DURATION_SECS),
                )
                .to_rhai_error()
        },
    );

    engine.register_fn(
        "benchmark_cpu_duration",
        |duration_sec: i64| -> Result<super::CPUBenchmarkResult, Box<EvalAltResult>> {
            use super::super::config::limits::cpu::*;
            if duration_sec < MIN_DURATION_SECS as i64 || duration_sec > MAX_DURATION_SECS as i64 {
                return Err(format!(
                    "duration_sec must be between {} and {}",
                    MIN_DURATION_SECS, MAX_DURATION_SECS
                )
                .into());
            }
            let profiler = super::profiler::CPUProfiler::new();
            profiler
                .run_benchmark(
                    DEFAULT_THREADS,
                    std::time::Duration::from_secs(duration_sec as u64),
                )
                .to_rhai_error()
        },
    );

    engine.register_fn(
        "benchmark_cpu_full",
        |threads: i64,
         duration_sec: i64|
         -> Result<super::CPUBenchmarkResult, Box<EvalAltResult>> {
            use super::super::config::limits::cpu::*;
            if threads < MIN_THREADS as i64 || threads > MAX_THREADS as i64 {
                return Err(format!(
                    "threads must be between {} and {}",
                    MIN_THREADS, MAX_THREADS
                )
                .into());
            }
            if duration_sec < MIN_DURATION_SECS as i64 || duration_sec > MAX_DURATION_SECS as i64 {
                return Err(format!(
                    "duration_sec must be between {} and {}",
                    MIN_DURATION_SECS, MAX_DURATION_SECS
                )
                .into());
            }
            let profiler = super::profiler::CPUProfiler::new();
            profiler
                .run_benchmark(
                    threads as u32,
                    std::time::Duration::from_secs(duration_sec as u64),
                )
                .to_rhai_error()
        },
    );

    Ok(())
}
