//! Rhai bindings for disk profiling functions

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

// Wrapper functions for cleaner registration
fn run_disk_benchmark(
    path: &str,
) -> Result<super::result::DiskBenchmarkResult, Box<EvalAltResult>> {
    let p = Path::new(path);
    super::profiler::run_disk_benchmark(p).to_rhai_error()
}

fn measure_sequential_read(
    path: &str,
    size_bytes: i64,
) -> Result<super::sequential::SequentialResult, Box<EvalAltResult>> {
    let p = Path::new(path);
    super::sequential::measure_sequential_read(p, size_bytes as u64).to_rhai_error()
}

fn measure_sequential_write(
    path: &str,
    size_bytes: i64,
) -> Result<super::sequential::SequentialResult, Box<EvalAltResult>> {
    let p = Path::new(path);
    super::sequential::measure_sequential_write(p, size_bytes as u64).to_rhai_error()
}

fn measure_random_read(
    path: &str,
    size_bytes: i64,
    block_size: i64,
) -> Result<super::random::RandomResult, Box<EvalAltResult>> {
    let p = Path::new(path);
    let bs = super::super::types::BlockSize::from_bytes(block_size as usize)
        .unwrap_or(super::super::types::BlockSize::Bytes4K);
    super::random::measure_random_read(p, size_bytes as u64, bs).to_rhai_error()
}

fn measure_random_write(
    path: &str,
    size_bytes: i64,
    block_size: i64,
) -> Result<super::random::RandomResult, Box<EvalAltResult>> {
    let p = Path::new(path);
    let bs = super::super::types::BlockSize::from_bytes(block_size as usize)
        .unwrap_or(super::super::types::BlockSize::Bytes4K);
    super::random::measure_random_write(p, size_bytes as u64, bs).to_rhai_error()
}

fn measure_iops(path: &str) -> Result<super::iops::IOPSResult, Box<EvalAltResult>> {
    super::iops::measure_iops(Path::new(path)).to_rhai_error()
}

fn test_disk_latency(path: &str) -> Result<super::latency::DiskLatencyResult, Box<EvalAltResult>> {
    super::latency::test_disk_latency(Path::new(path)).to_rhai_error()
}

/// Register disk profiling module with Rhai engine
pub fn register_disk_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
    // Register DiskBenchmarkResult type
    engine.register_type_with_name::<super::result::DiskBenchmarkResult>("DiskBenchmarkResult");
    engine.register_get("path", |result: &mut super::result::DiskBenchmarkResult| {
        result.path.to_string_lossy().to_string()
    });
    engine.register_get(
        "sequential_read",
        |result: &mut super::result::DiskBenchmarkResult| result.sequential_read.clone(),
    );
    engine.register_get(
        "sequential_write",
        |result: &mut super::result::DiskBenchmarkResult| result.sequential_write.clone(),
    );
    engine.register_get(
        "random_read",
        |result: &mut super::result::DiskBenchmarkResult| result.random_read.clone(),
    );
    engine.register_get(
        "random_write",
        |result: &mut super::result::DiskBenchmarkResult| result.random_write.clone(),
    );
    engine.register_get("iops", |result: &mut super::result::DiskBenchmarkResult| {
        result.iops.clone()
    });
    engine.register_get(
        "latency",
        |result: &mut super::result::DiskBenchmarkResult| result.latency.clone(),
    );

    // Register SequentialResult type
    engine.register_type::<super::sequential::SequentialResult>();
    engine.register_get(
        "throughput_mbps",
        |result: &mut super::sequential::SequentialResult| result.throughput_mbps,
    );
    engine.register_get(
        "total_bytes",
        |result: &mut super::sequential::SequentialResult| result.total_bytes,
    );
    engine.register_get(
        "duration",
        |result: &mut super::sequential::SequentialResult| result.duration,
    );

    // Register RandomResult type
    engine.register_type::<super::random::RandomResult>();
    engine.register_get(
        "throughput_mbps",
        |result: &mut super::random::RandomResult| result.throughput_mbps,
    );
    engine.register_get("iops", |result: &mut super::random::RandomResult| {
        result.iops
    });
    engine.register_get("block_size", |result: &mut super::random::RandomResult| {
        result.block_size
    });
    engine.register_get(
        "total_operations",
        |result: &mut super::random::RandomResult| result.total_operations,
    );

    // Register IOPSResult type
    engine.register_type::<super::iops::IOPSResult>();
    engine.register_get("read_iops", |result: &mut super::iops::IOPSResult| {
        result.read_iops
    });
    engine.register_get("write_iops", |result: &mut super::iops::IOPSResult| {
        result.write_iops
    });
    engine.register_get("mixed_iops", |result: &mut super::iops::IOPSResult| {
        result.mixed_iops
    });
    engine.register_get("block_size", |result: &mut super::iops::IOPSResult| {
        result.block_size
    });

    // Register DiskLatencyResult type
    engine.register_type::<super::latency::DiskLatencyResult>();
    engine.register_get(
        "read_latency_p50_us",
        |result: &mut super::latency::DiskLatencyResult| result.read_latency_p50_us,
    );
    engine.register_get(
        "read_latency_p95_us",
        |result: &mut super::latency::DiskLatencyResult| result.read_latency_p95_us,
    );
    engine.register_get(
        "read_latency_p99_us",
        |result: &mut super::latency::DiskLatencyResult| result.read_latency_p99_us,
    );
    engine.register_get(
        "write_latency_p50_us",
        |result: &mut super::latency::DiskLatencyResult| result.write_latency_p50_us,
    );
    engine.register_get(
        "write_latency_p95_us",
        |result: &mut super::latency::DiskLatencyResult| result.write_latency_p95_us,
    );
    engine.register_get(
        "write_latency_p99_us",
        |result: &mut super::latency::DiskLatencyResult| result.write_latency_p99_us,
    );

    engine.register_fn("run_disk_benchmark", run_disk_benchmark);
    engine.register_fn("measure_sequential_read", measure_sequential_read);
    engine.register_fn("measure_sequential_write", measure_sequential_write);
    engine.register_fn("measure_random_read", measure_random_read);
    engine.register_fn("measure_random_write", measure_random_write);
    engine.register_fn("measure_iops", measure_iops);
    engine.register_fn("test_disk_latency", test_disk_latency);

    // Register parameterized benchmark functions
    engine.register_fn("benchmark_disk", run_disk_benchmark);

    // Wrapper functions for parameterized benchmarks with error handling
    engine.register_fn(
        "benchmark_disk_with_path",
        |path: &str| -> super::result::DiskBenchmarkResult {
            super::profiler::run_disk_benchmark(&std::path::PathBuf::from(path)).unwrap_or_else(
                |_| {
                    log::error!("Disk benchmark with path failed");
                    super::result::DiskBenchmarkResult {
                        path: std::path::PathBuf::from(path),
                        sequential_read: super::sequential::SequentialResult {
                            throughput_mbps: 0.0,
                            total_bytes: 0,
                            duration: std::time::Duration::from_secs(1),
                        },
                        sequential_write: super::sequential::SequentialResult {
                            throughput_mbps: 0.0,
                            total_bytes: 0,
                            duration: std::time::Duration::from_secs(1),
                        },
                        random_read: super::random::RandomResult {
                            throughput_mbps: 0.0,
                            iops: 0.0,
                            block_size: 4096,
                            total_operations: 0,
                        },
                        random_write: super::random::RandomResult {
                            throughput_mbps: 0.0,
                            iops: 0.0,
                            block_size: 4096,
                            total_operations: 0,
                        },
                        iops: super::iops::IOPSResult {
                            read_iops: 0.0,
                            write_iops: 0.0,
                            mixed_iops: 0.0,
                            block_size: 4096,
                        },
                        latency: super::latency::DiskLatencyResult {
                            read_latency_p50_us: 0.0,
                            read_latency_p95_us: 0.0,
                            read_latency_p99_us: 0.0,
                            write_latency_p50_us: 0.0,
                            write_latency_p95_us: 0.0,
                            write_latency_p99_us: 0.0,
                        },
                    }
                },
            )
        },
    );

    engine.register_fn(
        "benchmark_disk_with_size",
        |path: &str, size_mb: i64| -> super::result::DiskBenchmarkResult {
            use super::super::config::limits::disk::*;
            if size_mb < MIN_SIZE_MB || size_mb > MAX_SIZE_MB {
                log::error!(
                    "size_mb must be between {} and {}",
                    MIN_SIZE_MB,
                    MAX_SIZE_MB
                );
                return super::result::DiskBenchmarkResult {
                    path: std::path::PathBuf::from(path),
                    sequential_read: super::sequential::SequentialResult {
                        throughput_mbps: 0.0,
                        total_bytes: 0,
                        duration: std::time::Duration::from_secs(1),
                    },
                    sequential_write: super::sequential::SequentialResult {
                        throughput_mbps: 0.0,
                        total_bytes: 0,
                        duration: std::time::Duration::from_secs(1),
                    },
                    random_read: super::random::RandomResult {
                        throughput_mbps: 0.0,
                        iops: 0.0,
                        block_size: 4096,
                        total_operations: 0,
                    },
                    random_write: super::random::RandomResult {
                        throughput_mbps: 0.0,
                        iops: 0.0,
                        block_size: 4096,
                        total_operations: 0,
                    },
                    iops: super::iops::IOPSResult {
                        read_iops: 0.0,
                        write_iops: 0.0,
                        mixed_iops: 0.0,
                        block_size: 4096,
                    },
                    latency: super::latency::DiskLatencyResult {
                        read_latency_p50_us: 0.0,
                        read_latency_p95_us: 0.0,
                        read_latency_p99_us: 0.0,
                        write_latency_p50_us: 0.0,
                        write_latency_p95_us: 0.0,
                        write_latency_p99_us: 0.0,
                    },
                };
            }
            let size_bytes = (size_mb * 1024 * 1024) as u64;
            super::profiler::run_disk_benchmark_with_size(
                &std::path::PathBuf::from(path),
                size_bytes,
            )
            .unwrap_or_else(|_| {
                log::error!("Disk benchmark with size failed");
                super::result::DiskBenchmarkResult {
                    path: std::path::PathBuf::from(path),
                    sequential_read: super::sequential::SequentialResult {
                        throughput_mbps: 0.0,
                        total_bytes: 0,
                        duration: std::time::Duration::from_secs(1),
                    },
                    sequential_write: super::sequential::SequentialResult {
                        throughput_mbps: 0.0,
                        total_bytes: 0,
                        duration: std::time::Duration::from_secs(1),
                    },
                    random_read: super::random::RandomResult {
                        throughput_mbps: 0.0,
                        iops: 0.0,
                        block_size: 4096,
                        total_operations: 0,
                    },
                    random_write: super::random::RandomResult {
                        throughput_mbps: 0.0,
                        iops: 0.0,
                        block_size: 4096,
                        total_operations: 0,
                    },
                    iops: super::iops::IOPSResult {
                        read_iops: 0.0,
                        write_iops: 0.0,
                        mixed_iops: 0.0,
                        block_size: 4096,
                    },
                    latency: super::latency::DiskLatencyResult {
                        read_latency_p50_us: 0.0,
                        read_latency_p95_us: 0.0,
                        read_latency_p99_us: 0.0,
                        write_latency_p50_us: 0.0,
                        write_latency_p95_us: 0.0,
                        write_latency_p99_us: 0.0,
                    },
                }
            })
        },
    );

    engine.register_fn(
        "benchmark_disk_sequential",
        |path: &str, size_mb: i64, operation: &str| -> super::sequential::SequentialResult {
            use super::super::config::limits::disk::*;
            if size_mb < MIN_SIZE_MB || size_mb > MAX_SIZE_MB {
                log::error!(
                    "size_mb must be between {} and {}",
                    MIN_SIZE_MB,
                    MAX_SIZE_MB
                );
                return super::sequential::SequentialResult {
                    throughput_mbps: 0.0,
                    total_bytes: 0,
                    duration: std::time::Duration::from_secs(1),
                };
            }
            let path_buf = std::path::PathBuf::from(path);
            let size_bytes = (size_mb * 1024 * 1024) as u64;
            let result = match operation {
                "read" => super::sequential::measure_sequential_read(&path_buf, size_bytes),
                "write" => super::sequential::measure_sequential_write(&path_buf, size_bytes),
                _ => {
                    log::error!("operation must be 'read' or 'write', got '{}'", operation);
                    return super::sequential::SequentialResult {
                        throughput_mbps: 0.0,
                        total_bytes: 0,
                        duration: std::time::Duration::from_secs(1),
                    };
                }
            };
            result.unwrap_or_else(|_| {
                log::error!("Disk sequential benchmark failed");
                super::sequential::SequentialResult {
                    throughput_mbps: 0.0,
                    total_bytes: 0,
                    duration: std::time::Duration::from_secs(1),
                }
            })
        },
    );

    Ok(())
}
