"""績效報告 HTML 產生器，使用 Plotly 產生互動式圖表。"""

from __future__ import annotations

import webbrowser

import numpy as np
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots


def generate_performance_html(
    trades: pd.DataFrame,
    summary: dict,
    params: dict | None = None,
    output_path: str = "performance.html",
    open_browser: bool = True,
) -> str:
    """產生 HTML 績效累積圖報告。

    Args:
        trades: 交易明細 DataFrame，必須包含 entry_date 和 profit_pct 欄位。
        summary: 績效摘要 dict，需包含 total_trades, win_rate_pct,
                 total_return_pct, annual_return_pct, max_drawdown_pct。
        params: 策略參數 dict，用於標題顯示。若為 None 則不顯示參數。
        output_path: HTML 輸出路徑。
        open_browser: 是否自動開啟瀏覽器，預設 True。

    Returns:
        output_path: 產生的 HTML 檔案路徑。
    """
    if trades.empty:
        print("無交易資料，跳過績效圖產生。")
        return output_path

    df = trades.copy()
    df["entry_date"] = pd.to_datetime(df["entry_date"])
    df = df.sort_values(["entry_date"]).reset_index(drop=True)

    daily = df.groupby("entry_date").agg(
        daily_profit=("profit_pct", "mean"),
        trades=("profit_pct", "count"),
        wins=("profit_pct", lambda x: (x > 0).sum()),
    ).reset_index()
    daily["cumulative_profit"] = daily["daily_profit"].cumsum()
    daily["peak"] = daily["cumulative_profit"].cummax()
    daily["drawdown"] = daily["cumulative_profit"] - daily["peak"]

    df["year"] = df["entry_date"].dt.year
    df["month"] = df["entry_date"].dt.month
    monthly_pivot = df.groupby(["year", "month"])["profit_pct"].sum().unstack(fill_value=0)

    fig = make_subplots(
        rows=4, cols=1,
        subplot_titles=(
            "累積報酬率 (%)",
            "每日報酬率 (%)",
            "回撤 (%)",
            "月度報酬率熱力圖 (%)",
        ),
        row_heights=[0.35, 0.2, 0.2, 0.25],
        vertical_spacing=0.06,
    )

    fig.add_trace(
        go.Scatter(
            x=daily["entry_date"], y=daily["cumulative_profit"] * 100,
            mode="lines+markers", name="累積報酬",
            line=dict(color="#1f77b4", width=2),
            marker=dict(size=4),
        ),
        row=1, col=1,
    )

    colors = ["#2ca02c" if v >= 0 else "#d62728" for v in daily["daily_profit"]]
    fig.add_trace(
        go.Bar(
            x=daily["entry_date"], y=daily["daily_profit"] * 100,
            name="每日報酬", marker_color=colors, opacity=0.8,
        ),
        row=2, col=1,
    )

    fig.add_trace(
        go.Scatter(
            x=daily["entry_date"], y=daily["drawdown"] * 100,
            mode="lines", name="回撤",
            fill="tozeroy", fillcolor="rgba(214,39,40,0.2)",
            line=dict(color="#d62728", width=1),
        ),
        row=3, col=1,
    )

    month_names = [f"{m}月" for m in monthly_pivot.columns]
    fig.add_trace(
        go.Heatmap(
            z=np.round(monthly_pivot.values * 100, 2),
            x=month_names,
            y=[str(y) for y in monthly_pivot.index],
            colorscale="RdYlGn", zmid=0,
            text=np.round(monthly_pivot.values * 100, 2),
            texttemplate="%{text}",
            name="月度報酬",
        ),
        row=4, col=1,
    )

    # 組裝標題
    title_parts = ["<b>策略績效報告</b>"]
    if params:
        param_strs = [f"{k}: {v}" for k, v in params.items()]
        title_parts.append(" | ".join(param_strs))

    summary_str = (
        f"總交易: {summary.get('total_trades', 'N/A')} | "
        f"勝率: {summary.get('win_rate_pct', 'N/A')}% | "
        f"累積報酬: {summary.get('total_return_pct', 'N/A')}% | "
        f"年化報酬: {summary.get('annual_return_pct', 'N/A')}% | "
        f"MDD: {summary.get('max_drawdown_pct', 'N/A')}%"
    )
    title_text = "<br>".join(title_parts) + f"<br>{summary_str}"

    fig.update_layout(
        title=dict(text=title_text, font=dict(size=14)),
        height=1200,
        showlegend=False,
        template="plotly_white",
    )

    fig.write_html(output_path)
    print(f"績效報告已儲存至 {output_path}")

    if open_browser:
        webbrowser.open(output_path)

    return output_path
