//! Rhai bindings for report functions

use rhai::{Engine, EvalAltResult};

/// Register report module with Rhai engine
pub fn register_report_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
    // Register BenchmarkReport type
    engine.register_type::<super::builder::BenchmarkReport>();
    engine.register_get(
        "schema_version",
        |result: &mut super::builder::BenchmarkReport| result.schema_version.clone(),
    );
    engine.register_get(
        "system_profile",
        |result: &mut super::builder::BenchmarkReport| result.system_profile.clone(),
    );
    engine.register_get(
        "timestamp",
        |result: &mut super::builder::BenchmarkReport| result.timestamp.clone(),
    );
    engine.register_get(
        "duration",
        |result: &mut super::builder::BenchmarkReport| result.duration,
    );
    engine.register_get(
        "benchmark_id",
        |result: &mut super::builder::BenchmarkReport| result.benchmark_id.clone(),
    );
    engine.register_get(
        "environment",
        |result: &mut super::builder::BenchmarkReport| result.environment.clone(),
    );
    engine.register_get(
        "git_commit",
        |result: &mut super::builder::BenchmarkReport| result.git_commit.clone(),
    );
    engine.register_get("tags", |result: &mut super::builder::BenchmarkReport| {
        result.tags.clone()
    });

    // Register BenchmarkReport constructor
    engine.register_fn("BenchmarkReport", || super::builder::BenchmarkReport::new());

    // Register BenchmarkReport methods
    engine.register_fn(
        "set_system_profile",
        |report: &mut super::builder::BenchmarkReport,
         profile: crate::profiling::system::SystemProfile| {
            report.set_system_profile(profile);
        },
    );

    engine.register_fn(
        "set_environment",
        |report: &mut super::builder::BenchmarkReport, environment: &str| {
            report.set_environment(environment);
        },
    );

    engine.register_fn(
        "set_git_commit",
        |report: &mut super::builder::BenchmarkReport, commit: &str| {
            report.set_git_commit(commit);
        },
    );

    engine.register_fn(
        "add_tag",
        |report: &mut super::builder::BenchmarkReport, key: &str, value: &str| {
            report.add_tag(key, value);
        },
    );

    engine.register_fn(
        "add_cpu_result",
        |report: &mut super::builder::BenchmarkReport,
         result: super::super::cpu::CPUBenchmarkResult| {
            match report.add_cpu_result(result) {
                Ok(_) => (),
                Err(e) => {
                    super::super::logging::log_error(&format!("Failed to add CPU result: {}", e));
                }
            }
        },
    );

    engine.register_fn(
        "add_memory_result",
        |report: &mut super::builder::BenchmarkReport,
         result: super::super::memory::bandwidth::MemoryBandwidthResult| {
            match report.add_memory_result(result) {
                Ok(_) => (),
                Err(e) => {
                    super::super::logging::log_error(&format!(
                        "Failed to add memory result: {}",
                        e
                    ));
                }
            }
        },
    );

    engine.register_fn(
        "add_disk_result",
        |report: &mut super::builder::BenchmarkReport,
         result: super::super::disk::result::DiskBenchmarkResult| {
            match report.add_disk_result(result) {
                Ok(_) => (),
                Err(e) => {
                    super::super::logging::log_error(&format!("Failed to add disk result: {}", e));
                }
            }
        },
    );

    engine.register_fn(
        "add_network_result",
        |report: &mut super::builder::BenchmarkReport,
         result: super::super::network::IperfResult| {
            match report.add_network_result(result) {
                Ok(_) => (),
                Err(e) => {
                    super::super::logging::log_error(&format!(
                        "Failed to add network result: {}",
                        e
                    ));
                }
            }
        },
    );

    // Overload for BandwidthResult (from measure_bandwidth)
    engine.register_fn(
        "add_network_result",
        |report: &mut super::builder::BenchmarkReport,
         result: super::super::network::BandwidthResult| {
            // Convert BandwidthResult to IperfResult for storage
            let iperf_result = super::super::network::IperfResult {
                config: super::super::network::IperfConfig {
                    server: "localhost".to_string(),
                    port: 5201,
                    duration: std::time::Duration::from_secs(5),
                    parallel_streams: 1,
                    window_size: None,
                    protocol: super::super::network::Protocol::Tcp,
                    bandwidth_limit: None,
                    reverse: false,
                },
                bandwidth_bps: result.download_bps.max(result.upload_bps),
                retransmits: None,
                jitter_ms: None,
                packet_loss_percent: None,
                duration: std::time::Duration::from_secs(5),
            };
            match report.add_network_result(iperf_result) {
                Ok(_) => (),
                Err(e) => {
                    super::super::logging::log_error(&format!(
                        "Failed to add network result: {}",
                        e
                    ));
                }
            }
        },
    );

    engine.register_fn(
        "generate_json",
        |report: &mut super::builder::BenchmarkReport| {
            super::formats::generate_json(report).unwrap_or_else(|_| "{}".to_string())
        },
    );

    engine.register_fn(
        "generate_text",
        |report: &mut super::builder::BenchmarkReport| {
            super::formats::generate_text(report)
                .unwrap_or_else(|_| "Report generation failed".to_string())
        },
    );

    engine.register_fn(
        "generate_html",
        |report: &mut super::builder::BenchmarkReport| {
            super::formats::generate_html(report).unwrap_or_else(|_| {
                "<html><body>Report generation failed</body></html>".to_string()
            })
        },
    );

    engine.register_fn(
        "export_to_csv",
        |report: &mut super::builder::BenchmarkReport, path: &str| match report
            .export_to_csv(std::path::Path::new(path))
        {
            Ok(_) => {
                super::super::logging::log_info(&format!("CSV exported to {}", path));
                true
            }
            Err(e) => {
                super::super::logging::log_error(&format!("Failed to export CSV: {}", e));
                false
            }
        },
    );

    // Register ComparisonResult type and getters
    engine.register_type::<super::comparison::ComparisonResult>();
    engine.register_get(
        "timestamp",
        |r: &mut super::comparison::ComparisonResult| r.timestamp.clone(),
    );
    engine.register_get(
        "cpu_delta_percent",
        |r: &mut super::comparison::ComparisonResult| r.cpu_delta_percent,
    );
    engine.register_get(
        "memory_delta_percent",
        |r: &mut super::comparison::ComparisonResult| r.memory_delta_percent,
    );
    engine.register_get(
        "disk_delta_percent",
        |r: &mut super::comparison::ComparisonResult| r.disk_delta_percent,
    );
    engine.register_get(
        "network_delta_percent",
        |r: &mut super::comparison::ComparisonResult| r.network_delta_percent,
    );
    engine.register_get(
        "regressions",
        |r: &mut super::comparison::ComparisonResult| r.regressions.clone(),
    );
    engine.register_get(
        "improvements",
        |r: &mut super::comparison::ComparisonResult| r.improvements.clone(),
    );
    engine.register_get(
        "schema_compatible",
        |r: &mut super::comparison::ComparisonResult| r.schema_compatible,
    );
    engine.register_get("warnings", |r: &mut super::comparison::ComparisonResult| {
        r.warnings.clone()
    });

    // Register compare_baselines method on BenchmarkReport
    engine.register_fn(
        "compare_baselines",
        |current: &mut super::builder::BenchmarkReport,
         baseline: super::builder::BenchmarkReport| {
            current.compare_baselines(&baseline)
        },
    );

    // Register function to load report from JSON string
    // Returns report with schema_version="ERROR" on failure so user can check
    engine.register_fn(
        "load_report_json",
        |json: &str| match serde_json::from_str::<super::builder::BenchmarkReport>(json) {
            Ok(report) => report,
            Err(e) => {
                super::super::logging::log_error(&format!("Failed to parse report JSON: {}", e));
                let mut err_report = super::builder::BenchmarkReport::new();
                err_report.schema_version = "ERROR".to_string();
                err_report
            }
        },
    );

    // Register function to load report from file
    // Returns report with schema_version="ERROR" on failure so user can check
    engine.register_fn(
        "load_report_file",
        |path: &str| match std::fs::read_to_string(path) {
            Ok(json) => match serde_json::from_str::<super::builder::BenchmarkReport>(&json) {
                Ok(report) => report,
                Err(e) => {
                    super::super::logging::log_error(&format!("Failed to parse report: {}", e));
                    let mut err_report = super::builder::BenchmarkReport::new();
                    err_report.schema_version = "ERROR".to_string();
                    err_report
                }
            },
            Err(e) => {
                super::super::logging::log_error(&format!("Failed to read file {}: {}", path, e));
                let mut err_report = super::builder::BenchmarkReport::new();
                err_report.schema_version = "ERROR".to_string();
                err_report
            }
        },
    );

    // Helper to check if report loaded successfully
    engine.register_fn(
        "is_valid_report",
        |report: &mut super::builder::BenchmarkReport| report.schema_version != "ERROR",
    );

    // Register function to save report to file
    engine.register_fn(
        "save_report_file",
        |report: &mut super::builder::BenchmarkReport, path: &str| {
            let json = super::formats::generate_json(report).unwrap_or_else(|_| "{}".to_string());
            match std::fs::write(path, &json) {
                Ok(_) => {
                    super::super::logging::log_info(&format!("Report saved to {}", path));
                    true
                }
                Err(e) => {
                    super::super::logging::log_error(&format!("Failed to save report: {}", e));
                    false
                }
            }
        },
    );

    // Register standalone compare function for two reports
    engine.register_fn(
        "compare_reports",
        |current: super::builder::BenchmarkReport, baseline: super::builder::BenchmarkReport| {
            super::comparison::compare_baselines(&current, &baseline)
        },
    );

    // Convenience function to run full benchmark and return populated report
    engine.register_fn("run_full_benchmark", |disk_path: &str| {
        let mut report = super::builder::BenchmarkReport::new();

        // Set system profile
        if let Ok(profile) = crate::profiling::system::SystemProfile::detect() {
            report.set_system_profile(profile);
        }

        // Run CPU benchmark (use 4 threads, 10 second duration)
        if let Ok(cpu_result) =
            crate::profiling::cpu::run_cpu_benchmark(4, std::time::Duration::from_secs(10))
        {
            let _ = report.add_cpu_result(cpu_result);
        }

        // Run memory benchmark
        if let Ok(mem_result) = crate::profiling::memory::measure_memory_bandwidth() {
            let _ = report.add_memory_result(mem_result);
        }

        // Run disk benchmark
        if let Ok(disk_result) =
            crate::profiling::disk::run_disk_benchmark(std::path::Path::new(disk_path))
        {
            let _ = report.add_disk_result(disk_result);
        }

        report
    });

    // Register trend analysis types
    engine.register_type::<super::trend::TrendAnalysis>();
    engine.register_type::<super::trend::TrendDirection>();
    engine.register_type::<super::trend::Statistics>();
    engine.register_type::<super::trend::Regression>();
    engine.register_type::<super::trend::RegressionSeverity>();

    // Register to_string for TrendDirection
    engine.register_fn("to_string", |d: super::trend::TrendDirection| {
        format!("{:?}", d)
    });

    // Register to_string for RegressionSeverity
    engine.register_fn("to_string", |s: super::trend::RegressionSeverity| {
        format!("{:?}", s)
    });

    // Register to_string for Option<String> (for environment, git_commit)
    engine.register_fn("to_string", |opt: &mut Option<String>| match opt {
        Some(s) => s.clone(),
        None => "None".to_string(),
    });

    // Register to_string for Option<f64> (for statistics)
    engine.register_fn("to_string", |opt: Option<f64>| match opt {
        Some(v) => format!("{}", v),
        None => "None".to_string(),
    });

    // Register to_string for HashMap<String, String> (for tags)
    engine.register_fn(
        "to_string",
        |map: std::collections::HashMap<String, String>| {
            if map.is_empty() {
                "{}".to_string()
            } else {
                let pairs: Vec<String> = map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
                format!("{{{}}}", pairs.join(", "))
            }
        },
    );

    // Register to_string for Vec<Regression> (for regression arrays)
    engine.register_fn("to_string", |regressions: Vec<super::trend::Regression>| {
        if regressions.is_empty() {
            "[]".to_string()
        } else {
            let items: Vec<String> = regressions
                .iter()
                .map(|r| {
                    format!(
                        "{{metric: {}, delta: {:.2}%, severity: {:?}}}",
                        r.metric, r.delta_percent, r.severity
                    )
                })
                .collect();
            format!("[{}]", items.join(", "))
        }
    });

    // Register TrendAnalysis getters
    engine.register_get("metric", |t: &mut super::trend::TrendAnalysis| {
        t.metric.clone()
    });
    engine.register_get("direction", |t: &mut super::trend::TrendAnalysis| {
        t.direction
    });
    engine.register_get("mean", |t: &mut super::trend::TrendAnalysis| t.mean);
    engine.register_get("stddev", |t: &mut super::trend::TrendAnalysis| t.stddev);
    engine.register_get("min", |t: &mut super::trend::TrendAnalysis| t.min);
    engine.register_get("max", |t: &mut super::trend::TrendAnalysis| t.max);
    engine.register_get("slope", |t: &mut super::trend::TrendAnalysis| t.slope);
    engine.register_get("sample_count", |t: &mut super::trend::TrendAnalysis| {
        t.sample_count as i64
    });

    // Register Statistics getters
    engine.register_get("cpu_mean", |s: &mut super::trend::Statistics| s.cpu_mean);
    engine.register_get("cpu_stddev", |s: &mut super::trend::Statistics| {
        s.cpu_stddev
    });
    engine.register_get("memory_mean", |s: &mut super::trend::Statistics| {
        s.memory_mean
    });
    engine.register_get("memory_stddev", |s: &mut super::trend::Statistics| {
        s.memory_stddev
    });
    engine.register_get("disk_mean", |s: &mut super::trend::Statistics| s.disk_mean);
    engine.register_get("disk_stddev", |s: &mut super::trend::Statistics| {
        s.disk_stddev
    });
    engine.register_get("network_mean", |s: &mut super::trend::Statistics| {
        s.network_mean
    });
    engine.register_get("network_stddev", |s: &mut super::trend::Statistics| {
        s.network_stddev
    });
    engine.register_get("sample_count", |s: &mut super::trend::Statistics| {
        s.sample_count as i64
    });

    // Register Regression getters
    engine.register_get("metric", |r: &mut super::trend::Regression| {
        r.metric.clone()
    });
    engine.register_get("timestamp", |r: &mut super::trend::Regression| {
        r.timestamp.clone()
    });
    engine.register_get("value", |r: &mut super::trend::Regression| r.value);
    engine.register_get("baseline_mean", |r: &mut super::trend::Regression| {
        r.baseline_mean
    });
    engine.register_get("delta_percent", |r: &mut super::trend::Regression| {
        r.delta_percent
    });
    engine.register_get("severity", |r: &mut super::trend::Regression| r.severity);

    // Register trend analysis functions
    engine.register_fn("analyze_trend", |reports: rhai::Array, metric: &str| {
        let reports: Vec<super::builder::BenchmarkReport> = reports
            .into_iter()
            .filter_map(|r| r.try_cast::<super::builder::BenchmarkReport>())
            .collect();
        super::trend::analyze_trend(&reports, metric)
    });

    engine.register_fn(
        "detect_regressions",
        |reports: rhai::Array, threshold: f64| {
            let reports: Vec<super::builder::BenchmarkReport> = reports
                .into_iter()
                .filter_map(|r| r.try_cast::<super::builder::BenchmarkReport>())
                .collect();
            super::trend::detect_regressions(&reports, threshold)
        },
    );

    engine.register_fn("calculate_statistics", |reports: rhai::Array| {
        let reports: Vec<super::builder::BenchmarkReport> = reports
            .into_iter()
            .filter_map(|r| r.try_cast::<super::builder::BenchmarkReport>())
            .collect();
        super::trend::calculate_statistics(&reports)
    });

    Ok(())
}
