"""Comparison report generation.

This module provides report generation capabilities for strategy comparison,
including tables, charts, and recommendations.
"""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from enum import Enum
from typing import TYPE_CHECKING, Any

import numpy as np
from numpy.typing import NDArray

if TYPE_CHECKING:
    from openclaw.comparison.comparator import ComparisonResult
    from openclaw.comparison.metrics import ComparisonMetrics


class ReportFormat(str, Enum):
    """Report output format."""

    JSON = "json"
    MARKDOWN = "markdown"
    HTML = "html"
    CSV = "csv"


@dataclass
class ComparisonReport:
    """Report generator for strategy comparison.

    Attributes:
        title: Report title
        description: Report description
        include_charts: Whether to include chart data
        include_recommendations: Whether to include recommendations
        format: Output format
    """

    title: str = "Strategy Comparison Report"
    description: str = ""
    include_charts: bool = True
    include_recommendations: bool = True
    format: ReportFormat = ReportFormat.MARKDOWN

    def generate(
        self,
        result: ComparisonResult,
        format: ReportFormat | None = None,
    ) -> str:
        """Generate comparison report.

        Args:
            result: Comparison result to report on
            format: Override the default format

        Returns:
            Report string in the specified format
        """
        output_format = format or self.format

        if output_format == ReportFormat.JSON:
            return self._generate_json(result)
        elif output_format == ReportFormat.HTML:
            return self._generate_html(result)
        elif output_format == ReportFormat.CSV:
            return self._generate_csv(result)
        else:
            return self._generate_markdown(result)

    def _generate_markdown(self, result: ComparisonResult) -> str:
        """Generate Markdown report.

        Args:
            result: Comparison result

        Returns:
            Markdown formatted report
        """
        lines = []

        # Header
        lines.append(f"# {self.title}")
        lines.append("")
        if self.description:
            lines.append(self.description)
            lines.append("")

        # Summary
        lines.append("## Summary")
        lines.append("")
        lines.append(f"- **Total Strategies**: {len(result.metrics)}")
        lines.append(f"- **Best Strategy**: {result.best_strategy or 'N/A'}")
        lines.append("")

        # Performance Table
        lines.append("## Performance Metrics")
        lines.append("")
        lines.append(self._create_metrics_table(result))
        lines.append("")

        # Rankings
        if result.rankings:
            lines.append("## Rankings")
            lines.append("")
            lines.append(self._create_rankings_table(result))
            lines.append("")

        # Statistical Tests
        if result.statistical_tests:
            lines.append("## Statistical Tests")
            lines.append("")
            lines.append(self._create_statistical_tests_table(result))
            lines.append("")

        # Recommendations
        if self.include_recommendations and result.recommendations:
            lines.append("## Recommendations")
            lines.append("")
            for rec in result.recommendations:
                lines.append(f"- {rec}")
            lines.append("")

        # Chart Data
        if self.include_charts:
            lines.append("## Chart Data")
            lines.append("")
            lines.append(self._create_chart_data_section(result))
            lines.append("")

        return "\n".join(lines)

    def _create_metrics_table(self, result: ComparisonResult) -> str:
        """Create performance metrics table.

        Args:
            result: Comparison result

        Returns:
            Markdown table string
        """
        headers = [
            "Strategy",
            "Total Return",
            "Sharpe",
            "Max DD",
            "Win Rate",
            "Profit Factor",
            "Risk Level",
        ]

        lines = ["| " + " | ".join(headers) + " |"]
        lines.append("|" + "|".join([" --- " for _ in headers]) + "|")

        for metric in sorted(result.metrics, key=lambda m: m.total_return, reverse=True):
            row = [
                metric.strategy_name,
                f"{metric.total_return * 100:.2f}%",
                f"{metric.sharpe_ratio:.2f}",
                f"{metric.max_drawdown * 100:.2f}%",
                f"{metric.win_rate * 100:.1f}%",
                f"{metric.profit_factor:.2f}",
                metric.risk_level.value,
            ]
            lines.append("| " + " | ".join(row) + " |")

        return "\n".join(lines)

    def _create_rankings_table(self, result: ComparisonResult) -> str:
        """Create rankings table.

        Args:
            result: Comparison result

        Returns:
            Markdown table string
        """
        lines = []

        for metric_name, strategies in result.rankings.items():
            lines.append(f"### By {metric_name.replace('_', ' ').title()}")
            lines.append("")
            for i, strategy in enumerate(strategies[:5], 1):
                lines.append(f"{i}. {strategy}")
            lines.append("")

        return "\n".join(lines)

    def _create_statistical_tests_table(self, result: ComparisonResult) -> str:
        """Create statistical tests results table.

        Args:
            result: Comparison result

        Returns:
            Markdown table string
        """
        lines = []

        for test_name, test_data in result.statistical_tests.items():
            lines.append(f"### {test_name}")
            lines.append("")

            if isinstance(test_data, dict):
                for key, value in test_data.items():
                    if isinstance(value, float):
                        lines.append(f"- **{key}**: {value:.4f}")
                    else:
                        lines.append(f"- **{key}**: {value}")
            lines.append("")

        return "\n".join(lines)

    def _create_chart_data_section(self, result: ComparisonResult) -> str:
        """Create chart data section.

        Args:
            result: Comparison result

        Returns:
            Markdown string with chart data
        """
        lines = []

        # Prepare data for charts
        strategies = [m.strategy_name for m in result.metrics]
        returns = [m.total_return * 100 for m in result.metrics]
        sharpes = [m.sharpe_ratio for m in result.metrics]
        drawdowns = [m.max_drawdown * 100 for m in result.metrics]

        lines.append("### Returns Comparison (%)")
        lines.append("")
        lines.append("```json")
        lines.append(json.dumps({
            "labels": strategies,
            "data": returns,
        }, indent=2))
        lines.append("```")
        lines.append("")

        lines.append("### Sharpe Ratio Comparison")
        lines.append("")
        lines.append("```json")
        lines.append(json.dumps({
            "labels": strategies,
            "data": sharpes,
        }, indent=2))
        lines.append("```")
        lines.append("")

        lines.append("### Max Drawdown Comparison (%)")
        lines.append("")
        lines.append("```json")
        lines.append(json.dumps({
            "labels": strategies,
            "data": drawdowns,
        }, indent=2))
        lines.append("```")

        return "\n".join(lines)

    def _generate_json(self, result: ComparisonResult) -> str:
        """Generate JSON report.

        Args:
            result: Comparison result

        Returns:
            JSON formatted report
        """
        data = {
            "title": self.title,
            "description": self.description,
            "summary": {
                "total_strategies": len(result.metrics),
                "best_strategy": result.best_strategy,
            },
            "metrics": [m.to_dict() for m in result.metrics],
            "rankings": result.rankings,
            "statistical_tests": result.statistical_tests,
            "recommendations": result.recommendations,
        }

        return json.dumps(data, indent=2, default=str)

    def _generate_html(self, result: ComparisonResult) -> str:
        """Generate HTML report.

        Args:
            result: Comparison result

        Returns:
            HTML formatted report
        """
        lines = []

        lines.append("<!DOCTYPE html>")
        lines.append("<html>")
        lines.append("<head>")
        lines.append(f"<title>{self.title}</title>")
        lines.append("<style>")
        lines.append(self._get_html_styles())
        lines.append("</style>")
        lines.append("</head>")
        lines.append("<body>")

        # Header
        lines.append(f"<h1>{self.title}</h1>")
        if self.description:
            lines.append(f"<p>{self.description}</p>")

        # Summary
        lines.append("<h2>Summary</h2>")
        lines.append("<ul>")
        lines.append(f"<li>Total Strategies: {len(result.metrics)}</li>")
        lines.append(f"<li>Best Strategy: {result.best_strategy or 'N/A'}</li>")
        lines.append("</ul>")

        # Metrics Table
        lines.append("<h2>Performance Metrics</h2>")
        lines.append(self._create_html_metrics_table(result))

        # Rankings
        if result.rankings:
            lines.append("<h2>Rankings</h2>")
            lines.append(self._create_html_rankings(result))

        # Statistical Tests
        if result.statistical_tests:
            lines.append("<h2>Statistical Tests</h2>")
            lines.append(self._create_html_statistical_tests(result))

        # Recommendations
        if self.include_recommendations and result.recommendations:
            lines.append("<h2>Recommendations</h2>")
            lines.append("<ul>")
            for rec in result.recommendations:
                lines.append(f"<li>{rec}</li>")
            lines.append("</ul>")

        lines.append("</body>")
        lines.append("</html>")

        return "\n".join(lines)

    def _get_html_styles(self) -> str:
        """Get CSS styles for HTML report.

        Returns:
            CSS styles string
        """
        return """
            body {
                font-family: Arial, sans-serif;
                margin: 20px;
                background-color: #f5f5f5;
            }
            h1, h2 {
                color: #333;
            }
            table {
                border-collapse: collapse;
                width: 100%;
                background-color: white;
                margin: 10px 0;
            }
            th, td {
                border: 1px solid #ddd;
                padding: 12px;
                text-align: left;
            }
            th {
                background-color: #4CAF50;
                color: white;
            }
            tr:nth-child(even) {
                background-color: #f2f2f2;
            }
            tr:hover {
                background-color: #ddd;
            }
            ul {
                line-height: 1.6;
            }
            .highlight {
                background-color: #ffffcc;
            }
        """

    def _create_html_metrics_table(self, result: ComparisonResult) -> str:
        """Create HTML metrics table.

        Args:
            result: Comparison result

        Returns:
            HTML table string
        """
        lines = []
        lines.append("<table>")
        lines.append("<tr>")
        headers = [
            "Strategy",
            "Total Return",
            "Sharpe",
            "Max Drawdown",
            "Win Rate",
            "Risk Level",
        ]
        for header in headers:
            lines.append(f"<th>{header}</th>")
        lines.append("</tr>")

        for metric in sorted(result.metrics, key=lambda m: m.total_return, reverse=True):
            lines.append("<tr>")
            lines.append(f"<td>{metric.strategy_name}</td>")
            lines.append(f"<td>{metric.total_return * 100:.2f}%</td>")
            lines.append(f"<td>{metric.sharpe_ratio:.2f}</td>")
            lines.append(f"<td>{metric.max_drawdown * 100:.2f}%</td>")
            lines.append(f"<td>{metric.win_rate * 100:.1f}%</td>")
            lines.append(f"<td>{metric.risk_level.value}</td>")
            lines.append("</tr>")

        lines.append("</table>")
        return "\n".join(lines)

    def _create_html_rankings(self, result: ComparisonResult) -> str:
        """Create HTML rankings section.

        Args:
            result: Comparison result

        Returns:
            HTML string
        """
        lines = []

        for metric_name, strategies in result.rankings.items():
            lines.append(f"<h3>{metric_name.replace('_', ' ').title()}</h3>")
            lines.append("<ol>")
            for strategy in strategies[:5]:
                lines.append(f"<li>{strategy}</li>")
            lines.append("</ol>")

        return "\n".join(lines)

    def _create_html_statistical_tests(self, result: ComparisonResult) -> str:
        """Create HTML statistical tests section.

        Args:
            result: Comparison result

        Returns:
            HTML string
        """
        lines = []

        for test_name, test_data in result.statistical_tests.items():
            lines.append(f"<h3>{test_name}</h3>")
            lines.append("<ul>")

            if isinstance(test_data, dict):
                for key, value in test_data.items():
                    display_value = f"{value:.4f}" if isinstance(value, float) else str(value)
                    lines.append(f"<li><strong>{key}:</strong> {display_value}</li>")

            lines.append("</ul>")

        return "\n".join(lines)

    def _generate_csv(self, result: ComparisonResult) -> str:
        """Generate CSV report.

        Args:
            result: Comparison result

        Returns:
            CSV formatted report
        """
        lines = []

        # Header
        headers = [
            "Strategy",
            "Total Return",
            "Annualized Return",
            "Sharpe Ratio",
            "Sortino Ratio",
            "Max Drawdown",
            "Max DD Duration",
            "Win Rate",
            "Profit Factor",
            "Win/Loss Ratio",
            "Volatility",
            "Calmar Ratio",
            "Num Trades",
            "Avg Trade",
            "VaR 95%",
            "CVaR 95%",
            "Risk Level",
            "Risk Score",
            "Return/Risk Ratio",
        ]
        lines.append(",".join(headers))

        # Data rows
        for metric in result.metrics:
            row = [
                metric.strategy_name,
                f"{metric.total_return:.6f}",
                f"{metric.annualized_return:.6f}",
                f"{metric.sharpe_ratio:.4f}",
                f"{metric.sortino_ratio:.4f}",
                f"{metric.max_drawdown:.6f}",
                str(metric.max_drawdown_duration),
                f"{metric.win_rate:.6f}",
                f"{metric.profit_factor:.4f}",
                f"{metric.win_loss_ratio:.4f}",
                f"{metric.volatility:.6f}",
                f"{metric.calmar_ratio:.4f}",
                str(metric.num_trades),
                f"{metric.avg_trade:.4f}",
                f"{metric.var_95:.6f}",
                f"{metric.cvar_95:.6f}",
                metric.risk_level.value,
                f"{metric.risk_score:.4f}",
                f"{metric.return_risk_ratio:.4f}",
            ]
            lines.append(",".join(row))

        return "\n".join(lines)

    def save(
        self,
        result: ComparisonResult,
        filepath: str,
        format: ReportFormat | None = None,
    ) -> None:
        """Save report to file.

        Args:
            result: Comparison result
            filepath: Output file path
            format: Output format (inferred from extension if not specified)
        """
        output_format = format or self._infer_format_from_path(filepath)
        content = self.generate(result, output_format)

        with open(filepath, 'w', encoding='utf-8') as f:
            f.write(content)

    def _infer_format_from_path(self, filepath: str) -> ReportFormat:
        """Infer report format from file extension.

        Args:
            filepath: File path

        Returns:
            Inferred report format
        """
        filepath_lower = filepath.lower()

        if filepath_lower.endswith('.json'):
            return ReportFormat.JSON
        elif filepath_lower.endswith('.html'):
            return ReportFormat.HTML
        elif filepath_lower.endswith('.csv'):
            return ReportFormat.CSV
        else:
            return ReportFormat.MARKDOWN


def generate_quick_summary(result: ComparisonResult) -> str:
    """Generate a quick text summary of comparison results.

    Args:
        result: Comparison result

    Returns:
        Summary string
    """
    lines = []
    lines.append("=" * 60)
    lines.append("Strategy Comparison Summary")
    lines.append("=" * 60)
    lines.append("")

    lines.append(f"Total Strategies: {len(result.metrics)}")
    lines.append(f"Best Strategy: {result.best_strategy}")
    lines.append("")

    lines.append("Top 3 by Total Return:")
    sorted_by_return = sorted(
        result.metrics,
        key=lambda m: m.total_return,
        reverse=True,
    )[:3]

    for i, metric in enumerate(sorted_by_return, 1):
        lines.append(
            f"  {i}. {metric.strategy_name}: "
            f"{metric.total_return * 100:.2f}% "
            f"(Sharpe: {metric.sharpe_ratio:.2f})"
        )

    lines.append("")
    lines.append("Risk Analysis:")
    for level in ["conservative", "moderate", "aggressive", "speculative"]:
        count = sum(1 for m in result.metrics if m.risk_level.value == level)
        lines.append(f"  {level.capitalize()}: {count} strategies")

    lines.append("")
    lines.append("=" * 60)

    return "\n".join(lines)
