//! Markdown report generation

use std::fs::File;
use std::io::Write;
use crate::types::{BenchResult, HardwareInfo, BENCHMARK_ITERATIONS, WARMUP_ITERATIONS};

pub fn generate_markdown_report(results: &[BenchResult], hw_info: &HardwareInfo, filename: &str) -> std::io::Result<()> {
    let mut file = File::create(filename)?;

    writeln!(file, "# NumRs Performance Benchmarks")?;
    writeln!(file)?;
    writeln!(file, "## System Configuration")?;
    writeln!(file)?;
    writeln!(file, "- **CPU:** {}", hw_info.cpu)?;
    writeln!(file, "- **GPU:** {}", hw_info.gpu)?;
    writeln!(file, "- **RAM:** {} GB", hw_info.ram_gb)?;
    writeln!(file, "- **OS:** {}", hw_info.os)?;
    writeln!(file)?;
    writeln!(file, "## Benchmark Configuration")?;
    writeln!(file)?;
    writeln!(file, "- **Generated:** {}", chrono::Local::now().format("%Y-%m-%d %H:%M:%S"))?;
    writeln!(file, "- **Build:** Release mode with optimizations + MKL")?;
    writeln!(file, "- **Iterations:** {} (after {} warmup)", BENCHMARK_ITERATIONS, WARMUP_ITERATIONS)?;
    writeln!(file)?;

    // Group by operation
    let mut ops: Vec<String> = results.iter()
        .map(|r| r.operation.clone())
        .collect();
    ops.sort();
    ops.dedup();

    writeln!(file, "## Performance by Operation")?;
    writeln!(file)?;
    writeln!(file, "| Operation | Backend | Size | DType1 | DType2 | DType_Result | Mean Time | Std Dev | Throughput |")?;
    writeln!(file, "|-----------|---------|------|--------|--------|--------------|-----------|---------|------------|")?;

    for op in &ops {
        let op_results: Vec<_> = results.iter()
            .filter(|r| r.operation == *op)
            .collect();

        for result in op_results {
            let mean_str = format_time(result.mean_us);
            let std_dev_str = format_time(result.std_dev_us);
            let throughput_str = format_throughput(result.throughput_mops);
            let dtype2_display = result.dtype2.as_ref().map(|s| s.as_str()).unwrap_or("N/A");
            
            writeln!(
                file,
                "| {} | {} | {} | {} | {} | {} | {} | {} | {} |",
                result.operation,
                result.backend,
                result.size,
                result.dtype1,
                dtype2_display,
                result.dtype_res,
                mean_str,
                std_dev_str,
                throughput_str
            )?;
        }
    }

    writeln!(file)?;
    writeln!(file, "## Backend Comparison")?;
    writeln!(file)?;
    
    // Find unique backends
    let mut backends: Vec<String> = results.iter()
        .map(|r| r.backend.clone())
        .collect();
    backends.sort();
    backends.dedup();

    for backend in &backends {
        let backend_results: Vec<_> = results.iter()
            .filter(|r| r.backend == *backend)
            .collect();

        if let Some(fastest) = backend_results.iter().min_by(|a, b| {
            a.mean_us.partial_cmp(&b.mean_us).unwrap_or(std::cmp::Ordering::Equal)
        }) {
            writeln!(file, "**{}:** Fastest operation: {} ({}) - {}", 
                backend, fastest.operation, fastest.size, format_time(fastest.mean_us))?;
        }
    }

    writeln!(file)?;
    writeln!(file, "## Summary Statistics")?;
    writeln!(file)?;
    writeln!(file, "**Total Benchmarks:** {}", results.len())?;
    writeln!(file, "**Backends Tested:** {}", backends.len())?;
    writeln!(file, "**Operations Tested:** {}", ops.len())?;

    if let Some(highest_tp) = results.iter().max_by(|a, b| {
        a.throughput_mops.partial_cmp(&b.throughput_mops).unwrap_or(std::cmp::Ordering::Equal)
    }) {
        writeln!(file, "**Highest Throughput:** {} with {} ({}) - {}", 
            highest_tp.operation, highest_tp.backend, highest_tp.size, format_throughput(highest_tp.throughput_mops))?;
    }

    writeln!(file)?;
    writeln!(file, "---")?;
    writeln!(file, "*Generated by `cargo run --bin numrs-bench --release` (BLAS/MKL enabled by default)*")?;

    Ok(())
}

fn format_time(us: f64) -> String {
    if us < 1.0 {
        format!("{:.2} ns", us * 1000.0)
    } else if us < 1000.0 {
        format!("{:.2} μs", us)
    } else if us < 1_000_000.0 {
        format!("{:.2} ms", us / 1000.0)
    } else {
        format!("{:.2} s", us / 1_000_000.0)
    }
}

fn format_throughput(mops: f64) -> String {
    if mops < 1.0 {
        format!("{:.2} Kops/s", mops * 1000.0)
    } else if mops < 1000.0 {
        format!("{:.2} Mops/s", mops)
    } else if mops < 1_000_000.0 {
        format!("{:.2} Gops/s", mops / 1000.0)
    } else if mops < 1_000_000_000.0 {
        format!("{:.2} Tops/s", mops / 1_000_000.0)
    } else {
        format!("{:.2} Pops/s", mops / 1_000_000_000.0)
    }
}
