//! Report format generators

use std::fs::File;
use std::io::Write;
use std::path::Path;

use super::super::error::ProfilingError;
use super::builder::BenchmarkReport;

/// Generate JSON report
pub fn generate_json(report: &BenchmarkReport) -> Result<String, ProfilingError> {
    serde_json::to_string_pretty(report)
        .map_err(|e| ProfilingError::ParseError(format!("Failed to serialize JSON: {}", e)))
}

/// Generate text report
pub fn generate_text(report: &BenchmarkReport) -> Result<String, ProfilingError> {
    let mut output = String::new();

    output.push_str("=== System Profiling Report ===\n\n");

    if let Some(profile) = &report.system_profile {
        output.push_str("System Profile:\n");
        output.push_str(&format!("  Hostname: {}\n", profile.hostname));
        output.push_str(&format!(
            "  OS: {} {}\n",
            profile.os_name, profile.os_version
        ));
        output.push_str(&format!("  CPU: {}\n", profile.cpu_model));
        output.push_str(&format!(
            "  Cores: {} (Threads: {})\n",
            profile.cpu_cores, profile.cpu_threads
        ));
        output.push_str(&format!(
            "  Memory: {} MB\n\n",
            profile.memory_total_bytes / 1024 / 1024
        ));
    }

    if !report.network_results.is_empty() {
        output.push_str("Network Results:\n");
        for (i, result) in report.network_results.iter().enumerate() {
            output.push_str(&format!("  Test {}:\n", i + 1));
            output.push_str(&format!(
                "    Bandwidth: {:.2} Mbps\n",
                result.bandwidth_bps / 1_000_000.0
            ));
            output.push_str(&format!("    Duration: {:?}\n", result.duration));
            if let Some(jitter) = result.jitter_ms {
                output.push_str(&format!("    Jitter: {:.2} ms\n", jitter));
            }
            if let Some(loss) = result.packet_loss_percent {
                output.push_str(&format!("    Packet Loss: {:.2}%\n", loss));
            }
        }
        output.push_str("\n");
    }

    if !report.disk_results.is_empty() {
        output.push_str("Disk Results:\n");
        for (i, result) in report.disk_results.iter().enumerate() {
            output.push_str(&format!("  Test {}:\n", i + 1));
            output.push_str(&format!(
                "    Sequential Read: {:.2} MB/s\n",
                result.sequential_read.throughput_mbps
            ));
            output.push_str(&format!(
                "    Sequential Write: {:.2} MB/s\n",
                result.sequential_write.throughput_mbps
            ));
            output.push_str(&format!(
                "    Random Read: {:.2} MB/s\n",
                result.random_read.throughput_mbps
            ));
            output.push_str(&format!(
                "    Random Write: {:.2} MB/s\n",
                result.random_write.throughput_mbps
            ));
            output.push_str(&format!("    IOPS: {:.0}\n", result.iops.mixed_iops));
        }
        output.push_str("\n");
    }

    if !report.memory_results.is_empty() {
        output.push_str("Memory Results:\n");
        for (i, result) in report.memory_results.iter().enumerate() {
            output.push_str(&format!("  Test {}:\n", i + 1));
            output.push_str(&format!(
                "    Read Bandwidth: {:.2} GB/s\n",
                result.read_bandwidth_gbps
            ));
            output.push_str(&format!(
                "    Write Bandwidth: {:.2} GB/s\n",
                result.write_bandwidth_gbps
            ));
            output.push_str(&format!(
                "    Copy Bandwidth: {:.2} GB/s\n",
                result.copy_bandwidth_gbps
            ));
        }
        output.push_str("\n");
    }

    if !report.cpu_results.is_empty() {
        output.push_str("CPU Results:\n");
        for (i, result) in report.cpu_results.iter().enumerate() {
            output.push_str(&format!("  Test {}:\n", i + 1));
            output.push_str(&format!(
                "    Integer Score: {:.0}\n",
                result.single_thread.integer_score
            ));
            output.push_str(&format!(
                "    Float Score: {:.0}\n",
                result.single_thread.float_score
            ));
            output.push_str(&format!(
                "    Combined Score: {:.0}\n",
                result.single_thread.combined_score
            ));
            if let Some(ref scaling) = result.scaling {
                output.push_str(&format!(
                    "    Scaling Efficiency: {:.1}%\n",
                    scaling.scaling_efficiency * 100.0
                ));
            }
        }
        output.push_str("\n");
    }

    output.push_str(&format!("Generated: {}\n", report.timestamp));
    output.push_str(&format!("Total Duration: {:?}\n", report.duration));

    Ok(output)
}

/// Generate HTML report
pub fn generate_html(report: &BenchmarkReport) -> Result<String, ProfilingError> {
    let mut html = String::new();

    html.push_str("<!DOCTYPE html>\n");
    html.push_str("<html>\n<head>\n");
    html.push_str("<title>System Profiling Report</title>\n");
    html.push_str("<style>\n");
    html.push_str("body { font-family: Arial, sans-serif; margin: 20px; }\n");
    html.push_str("h1 { color: #333; }\n");
    html.push_str("h2 { color: #666; border-bottom: 1px solid #ddd; padding-bottom: 5px; }\n");
    html.push_str("table { border-collapse: collapse; width: 100%; margin: 20px 0; }\n");
    html.push_str("th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n");
    html.push_str("th { background-color: #f4f4f4; }\n");
    html.push_str(".metric { font-weight: bold; }\n");
    html.push_str("</style>\n");
    html.push_str("</head>\n<body>\n");

    html.push_str("<h1>System Profiling Report</h1>\n");

    if let Some(profile) = &report.system_profile {
        html.push_str("<h2>System Profile</h2>\n");
        html.push_str("<table>\n");
        html.push_str("<tr><th>Metric</th><th>Value</th></tr>\n");
        html.push_str(&format!(
            "<tr><td>Hostname</td><td>{}</td></tr>\n",
            profile.hostname
        ));
        html.push_str(&format!(
            "<tr><td>OS</td><td>{} {}</td></tr>\n",
            profile.os_name, profile.os_version
        ));
        html.push_str(&format!(
            "<tr><td>CPU</td><td>{}</td></tr>\n",
            profile.cpu_model
        ));
        html.push_str(&format!(
            "<tr><td>Cores</td><td>{} (Threads: {})</td></tr>\n",
            profile.cpu_cores, profile.cpu_threads
        ));
        html.push_str(&format!(
            "<tr><td>Memory</td><td>{} MB</td></tr>\n",
            profile.memory_total_bytes / 1024 / 1024
        ));
        html.push_str("</table>\n");
    }

    if !report.network_results.is_empty() {
        html.push_str("<h2>Network Results</h2>\n");
        html.push_str("<table>\n");
        html.push_str("<tr><th>Test</th><th>Bandwidth (Mbps)</th><th>Duration</th></tr>\n");
        for (i, result) in report.network_results.iter().enumerate() {
            html.push_str(&format!(
                "<tr><td>{}</td><td class=\"metric\">{:.2}</td><td>{:?}</td></tr>\n",
                i + 1,
                result.bandwidth_bps / 1_000_000.0,
                result.duration
            ));
        }
        html.push_str("</table>\n");
    }

    if !report.disk_results.is_empty() {
        html.push_str("<h2>Disk Results</h2>\n");
        html.push_str("<table>\n");
        html.push_str("<tr><th>Test</th><th>Seq Read (MB/s)</th><th>Seq Write (MB/s)</th><th>IOPS</th></tr>\n");
        for (i, result) in report.disk_results.iter().enumerate() {
            html.push_str(&format!(
                "<tr><td>{}</td><td>{:.2}</td><td>{:.2}</td><td class=\"metric\">{:.0}</td></tr>\n",
                i + 1,
                result.sequential_read.throughput_mbps,
                result.sequential_write.throughput_mbps,
                result.iops.mixed_iops
            ));
        }
        html.push_str("</table>\n");
    }

    html.push_str(&format!(
        "<p><em>Generated: {}</em></p>\n",
        report.timestamp
    ));
    html.push_str("</body>\n</html>");

    Ok(html)
}

/// Export to CSV format
pub fn export_to_csv(report: &BenchmarkReport, path: &Path) -> Result<(), ProfilingError> {
    let mut file = File::create(path)
        .map_err(|e| ProfilingError::IoError(format!("Failed to create CSV file: {}", e)))?;

    writeln!(file, "Benchmark Type,Metric,Value")
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;

    for result in &report.network_results {
        writeln!(
            file,
            "Network,Bandwidth (Mbps),{:.2}",
            result.bandwidth_bps / 1_000_000.0
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
    }

    for result in &report.disk_results {
        writeln!(
            file,
            "Disk,Sequential Read (MB/s),{:.2}",
            result.sequential_read.throughput_mbps
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
        writeln!(
            file,
            "Disk,Sequential Write (MB/s),{:.2}",
            result.sequential_write.throughput_mbps
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
        writeln!(file, "Disk,IOPS,{:.0}", result.iops.mixed_iops)
            .map_err(|e| ProfilingError::IoError(e.to_string()))?;
    }

    for result in &report.memory_results {
        writeln!(
            file,
            "Memory,Read Bandwidth (GB/s),{:.2}",
            result.read_bandwidth_gbps
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
        writeln!(
            file,
            "Memory,Write Bandwidth (GB/s),{:.2}",
            result.write_bandwidth_gbps
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
    }

    for result in &report.cpu_results {
        writeln!(
            file,
            "CPU,Combined Score,{:.0}",
            result.single_thread.combined_score
        )
        .map_err(|e| ProfilingError::IoError(e.to_string()))?;
    }

    Ok(())
}
