//! Backtest Report Generation
//!
//! Generates comparison reports in JSON, markdown, and console formats.

use std::fmt::Write as _;

use super::metrics::PerformanceMetrics;
use serde::{Deserialize, Serialize};

/// Backtest comparison report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BacktestReport {
    pub model_name: String,
    pub baseline_name: String,
    pub new_results: PerformanceMetrics,
    pub baseline_results: Option<PerformanceMetrics>,
}

impl BacktestReport {
    /// Generate markdown report with comparison to baseline
    pub fn generate_markdown(&self) -> String {
        let mut report = String::new();

        report.push_str("# DQN Backtest Report\n\n");

        // Model info
        _ = writeln!(report, "**Model**: {}", self.model_name);
        if let Some(ref _baseline) = self.baseline_results {
            _ = writeln!(report, "**Baseline**: {}\n", self.baseline_name);
        } else {
            report.push('\n');
        }

        // Results table
        report.push_str("## Performance Metrics\n\n");
        report.push_str("| Metric | New Model | Baseline | Change |\n");
        report.push_str("|--------|-----------|----------|--------|\n");

        let baseline_opt = &self.baseline_results;

        // Total Return
        self.add_metric_row(
            &mut report,
            "Total Return",
            &format!("{:.2}%", self.new_results.total_return_pct),
            baseline_opt
                .as_ref()
                .map(|b| format!("{:.2}%", b.total_return_pct)),
            baseline_opt
                .as_ref()
                .map(|b| self.new_results.total_return_pct - b.total_return_pct),
            "%",
        );

        // Sharpe Ratio
        self.add_metric_row(
            &mut report,
            "Sharpe Ratio",
            &format!("{:.2}", self.new_results.sharpe_ratio),
            baseline_opt
                .as_ref()
                .map(|b| format!("{:.2}", b.sharpe_ratio)),
            baseline_opt
                .as_ref()
                .map(|b| self.new_results.sharpe_ratio - b.sharpe_ratio),
            "",
        );

        // Max Drawdown
        self.add_metric_row(
            &mut report,
            "Max Drawdown",
            &format!("{:.2}%", self.new_results.max_drawdown_pct),
            baseline_opt
                .as_ref()
                .map(|b| format!("{:.2}%", b.max_drawdown_pct)),
            baseline_opt
                .as_ref()
                .map(|b| b.max_drawdown_pct - self.new_results.max_drawdown_pct), // Lower is better
            "%",
        );

        // Win Rate
        self.add_metric_row(
            &mut report,
            "Win Rate",
            &format!("{:.1}%", self.new_results.win_rate),
            baseline_opt.as_ref().map(|b| format!("{:.1}%", b.win_rate)),
            baseline_opt
                .as_ref()
                .map(|b| self.new_results.win_rate - b.win_rate),
            "%",
        );

        // Total Trades
        self.add_metric_row(
            &mut report,
            "Total Trades",
            &format!("{}", self.new_results.total_trades),
            baseline_opt.as_ref().map(|b| format!("{}", b.total_trades)),
            baseline_opt
                .as_ref()
                .map(|b| (self.new_results.total_trades as i64 - b.total_trades as i64) as f64),
            "",
        );

        report.push('\n');

        // Summary
        report.push_str("## Summary\n\n");
        if let Some(ref baseline) = self.baseline_results {
            let improved = self.new_results.sharpe_ratio > baseline.sharpe_ratio
                && self.new_results.total_return_pct > baseline.total_return_pct;

            if improved {
                report.push_str("✅ **New model outperforms baseline**\n\n");
            } else {
                report.push_str("⚠️  **New model underperforms baseline**\n\n");
            }
        } else {
            report.push_str("No baseline for comparison.\n\n");
        }

        report
    }

    /// Helper to add metric row with change calculation
    fn add_metric_row(
        &self,
        report: &mut String,
        name: &str,
        new_value: &str,
        baseline_value: Option<String>,
        change: Option<f64>,
        suffix: &str,
    ) {
        let baseline_str = baseline_value.unwrap_or_else(|| "--".to_owned());
        let change_str = if let Some(c) = change {
            let sign = if c > 0.0 { "+" } else { "" };
            format!("{}{:.2}{}", sign, c, suffix)
        } else {
            "--".to_owned()
        };

        _ = writeln!(
            report,
            "| {} | {} | {} | {} |",
            name, new_value, baseline_str, change_str
        );
    }
}
