"""MAE/MFE Analysis Workflow - 5-Step Analysis Framework.

This module provides structured analysis methods following the MAE/MFE workflow:

A. Volatility Stability Analysis (波動穩定性)
B. Entry Timing Analysis (進場時機)
C. Stop Loss / Take Profit Analysis (停損停利)
D. Trailing Stop / Breakeven Analysis (追蹤停損/損益兩平)
E. Position Sizing Analysis (加減碼)
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

import polars as pl

if TYPE_CHECKING:
    import plotly.graph_objects as go

    from ..mae_mfe.config import ChartConfig


def _import_plotly() -> tuple:
    """Lazy import Plotly."""
    try:
        import plotly.graph_objects as go
        from plotly.subplots import make_subplots

        return go, make_subplots
    except ImportError as e:
        raise ImportError(
            "Plotly is required for workflow analysis. Install with: pip install plotly>=6.3.1"
        ) from e


@dataclass
class QuantileStats:
    """Quantile statistics for a metric."""

    q1: float  # 25th percentile
    q2: float  # 50th percentile (median)
    q3: float  # 75th percentile
    mean: float
    std: float
    min: float
    max: float

    @property
    def iqr(self) -> float:
        """Interquartile range (Q3 - Q1)."""
        return self.q3 - self.q1

    @property
    def q1_q2_mid(self) -> float:
        """Midpoint between Q1 and Q2."""
        return (self.q1 + self.q2) / 2

    @property
    def q2_q3_mid(self) -> float:
        """Midpoint between Q2 and Q3."""
        return (self.q2 + self.q3) / 2


@dataclass
class MAEMFEQuantiles:
    """Quantile statistics for MAE and MFE metrics."""

    mae: QuantileStats
    mfe: QuantileStats
    g_mfe: QuantileStats | None  # MFE before MAE
    mhl: QuantileStats | None  # Max High-Low


@dataclass
class EntryDelayRecommendation:
    """Recommendation for entry delay based on MAE/MFE analysis."""

    should_delay: bool
    delay_price: float | None  # Suggested delay price (from MAE Q1)
    delay_price_conservative: float | None  # More conservative (Q1+Q2)/2
    reason: str
    mae_mfe_ratio: float  # Upper-right corner ratio


@dataclass
class SLTPRecommendation:
    """Stop Loss / Take Profit recommendation."""

    # Basic recommendations
    sl_raw: float
    tp_raw: float
    sl_atr: float | None
    tp_atr: float | None

    # Cluster-based (from quadrant analysis)
    cluster_sl: float | None
    cluster_tp: float | None

    # Risk/Reward
    risk_reward_ratio: float
    expected_win_rate_for_breakeven: float


@dataclass
class TrailingStopRecommendation:
    """Trailing stop and breakeven recommendation."""

    # Breakeven trigger (from lose trade MFE)
    breakeven_trigger_q1_q2: float
    breakeven_trigger_q2: float

    # Trailing distance (from MHL)
    trailing_distance_q2: float
    trailing_distance_q3: float

    # Has inverse relationship (suitable for trailing)
    has_inverse_relationship: bool


@dataclass
class PositionSizingRecommendation:
    """Position sizing (add/reduce) recommendation."""

    # Adverse direction add (for high win rate, large loss strategies)
    adverse_add_zone_start: float  # Win MAE Q1
    adverse_add_zone_end: float  # Win MAE Q2
    adverse_reduce_zone: float  # Win MAE Q2-Q3

    # Favorable direction add
    favorable_add_zone_start: float  # Win MFE Q2
    favorable_add_zone_end: float  # Win MFE Q3
    favorable_crossover_point: float | None  # Win/Lose MFE crossover

    # Reduce position (take profit)
    reduce_zone: float  # 1/2 to 1/3 between add and TP


def calculate_quantiles(series: pl.Series) -> QuantileStats:
    """Calculate quantile statistics for a series."""
    return QuantileStats(
        q1=series.quantile(0.25),
        q2=series.quantile(0.5),
        q3=series.quantile(0.75),
        mean=series.mean(),
        std=series.std() or 0.0,
        min=series.min(),
        max=series.max(),
    )


def calculate_mae_mfe_quantiles(df: pl.DataFrame) -> MAEMFEQuantiles:
    """Calculate quantiles for all MAE/MFE metrics."""
    mae_stats = calculate_quantiles(df["mae"]) if "mae" in df.columns else None
    mfe_stats = calculate_quantiles(df["mfe"]) if "mfe" in df.columns else None
    g_mfe_stats = calculate_quantiles(df["g_mfe"]) if "g_mfe" in df.columns else None
    mhl_stats = calculate_quantiles(df["mhl"]) if "mhl" in df.columns else None

    if mae_stats is None or mfe_stats is None:
        raise ValueError("DataFrame must contain 'mae' and 'mfe' columns")

    return MAEMFEQuantiles(
        mae=mae_stats,
        mfe=mfe_stats,
        g_mfe=g_mfe_stats,
        mhl=mhl_stats,
    )


# =============================================================================
# Step A: Volatility Stability Analysis
# =============================================================================


def timeseries_mae_mfe(
    df: pl.DataFrame,
    config: ChartConfig,
    include_g_mfe: bool = True,
) -> go.Figure:
    """A1: Time series plot of MAE, MFE, and optionally g_mfe.

    Args:
        df: Trades DataFrame with exit_time column.
        config: Chart configuration.
        include_g_mfe: Whether to include MFE before MAE.

    Returns:
        Plotly Figure with time series.
    """
    go, _ = _import_plotly()

    if "exit_time" not in df.columns:
        raise ValueError("exit_time column required for time series")

    # Sort by exit time
    sorted_df = df.sort("exit_time")
    times = sorted_df["exit_time"].to_list()

    fig = go.Figure()

    # MAE
    if "mae" in sorted_df.columns:
        fig.add_trace(
            go.Scatter(
                x=times,
                y=sorted_df["mae"].to_list(),
                mode="lines+markers",
                name="MAE",
                marker=dict(size=4),
                line=dict(color=config.color_loser),
            )
        )

    # MFE
    if "mfe" in sorted_df.columns:
        fig.add_trace(
            go.Scatter(
                x=times,
                y=sorted_df["mfe"].to_list(),
                mode="lines+markers",
                name="MFE",
                marker=dict(size=4),
                line=dict(color=config.color_winner),
            )
        )

    # g_mfe (MFE before MAE)
    if include_g_mfe and "g_mfe" in sorted_df.columns:
        fig.add_trace(
            go.Scatter(
                x=times,
                y=sorted_df["g_mfe"].to_list(),
                mode="lines+markers",
                name="MFE before MAE",
                marker=dict(size=4),
                line=dict(color=config.color_long, dash="dash"),
            )
        )

    fig.update_layout(
        title="A1: MAE/MFE Time Series",
        xaxis_title="Exit Time",
        yaxis_title="Value",
        template=config.theme,
        width=config.width,
        height=config.height,
        showlegend=True,
    )

    return fig


def volatility_stability_analysis(
    df: pl.DataFrame,
    config: ChartConfig,
    window: int = 20,
) -> go.Figure:
    """A2-A5: Analyze volatility stability with rolling statistics.

    Args:
        df: Trades DataFrame.
        config: Chart configuration.
        window: Rolling window size for stability analysis.

    Returns:
        Plotly Figure with stability metrics.
    """
    go, make_subplots = _import_plotly()

    if "exit_time" not in df.columns:
        raise ValueError("exit_time column required")

    sorted_df = df.sort("exit_time")

    fig = make_subplots(
        rows=3,
        cols=1,
        subplot_titles=(
            "A2: MAE Stability (Rolling Std)",
            "A4: MFE vs g_mfe Overlap",
            "A5: MAE/MFE Ratio Over Time",
        ),
        vertical_spacing=0.1,
    )

    times = sorted_df["exit_time"].to_list()

    # A2: MAE stability (rolling std)
    if "mae" in sorted_df.columns:
        mae_values = sorted_df["mae"].to_list()
        rolling_std = []
        for i in range(len(mae_values)):
            start = max(0, i - window + 1)
            window_data = mae_values[start : i + 1]
            if len(window_data) > 1:
                mean = sum(window_data) / len(window_data)
                var = sum((x - mean) ** 2 for x in window_data) / len(window_data)
                rolling_std.append(var**0.5)
            else:
                rolling_std.append(0)

        fig.add_trace(
            go.Scatter(x=times, y=rolling_std, mode="lines", name="MAE Rolling Std"),
            row=1,
            col=1,
        )

    # A4: MFE vs g_mfe overlap
    if "mfe" in sorted_df.columns and "g_mfe" in sorted_df.columns:
        mfe_vals = sorted_df["mfe"].to_list()
        g_mfe_vals = sorted_df["g_mfe"].to_list()

        # Calculate overlap ratio (g_mfe / mfe)
        overlap_ratio = [g / m if m > 0 else 1.0 for g, m in zip(g_mfe_vals, mfe_vals)]

        fig.add_trace(
            go.Scatter(
                x=times,
                y=overlap_ratio,
                mode="lines",
                name="g_mfe/mfe Ratio",
                line=dict(color=config.color_long),
            ),
            row=2,
            col=1,
        )
        # Add reference line at 1.0
        fig.add_hline(y=1.0, line_dash="dash", line_color="gray", row=2, col=1)

    # A5: MAE/MFE ratio over time
    if "mae" in sorted_df.columns and "mfe" in sorted_df.columns:
        mae_vals = sorted_df["mae"].to_list()
        mfe_vals = sorted_df["mfe"].to_list()
        ratio = [m / f if f > 0 else 0 for m, f in zip(mae_vals, mfe_vals)]

        fig.add_trace(
            go.Scatter(
                x=times,
                y=ratio,
                mode="lines",
                name="MAE/MFE Ratio",
                line=dict(color=config.color_neutral),
            ),
            row=3,
            col=1,
        )
        # Add reference line at 1.0
        fig.add_hline(y=1.0, line_dash="dash", line_color="gray", row=3, col=1)

    fig.update_layout(
        title="Volatility Stability Analysis (Step A)",
        template=config.theme,
        width=config.width,
        height=config.height * 1.5,
        showlegend=True,
    )

    return fig


def mfe_g_mfe_overlap_score(df: pl.DataFrame) -> float:
    """A4: Calculate overlap score between MFE and g_mfe.

    Returns value between 0-1, where:
    - 1.0 = perfect overlap (g_mfe == mfe always)
    - 0.0 = no overlap (g_mfe always much smaller than mfe)

    Higher overlap -> prioritize SL/TP (Step C)
    Lower overlap -> prioritize trailing stop (Step D)
    """
    if "mfe" not in df.columns or "g_mfe" not in df.columns:
        return 1.0  # Default to high overlap if g_mfe not available

    # Calculate ratio for each trade
    ratios = df.select(
        pl.when(pl.col("mfe") > 0)
        .then(pl.col("g_mfe") / pl.col("mfe"))
        .otherwise(1.0)
        .alias("ratio")
    )["ratio"]

    # Average ratio, capped at 1.0
    return min(ratios.mean(), 1.0)


# =============================================================================
# Step B: Entry Timing Analysis
# =============================================================================


def entry_timing_scatter(
    df: pl.DataFrame,
    config: ChartConfig,
    equal_scale: bool = True,
) -> go.Figure:
    """B1: MAE/MFE scatter with equal axis scale.

    Args:
        df: Trades DataFrame.
        config: Chart configuration.
        equal_scale: Whether to use equal axis scales.

    Returns:
        Plotly Figure.
    """
    go, _ = _import_plotly()

    if "mae" not in df.columns or "mfe" not in df.columns:
        raise ValueError("mae and mfe columns required")

    mae_vals = df["mae"].to_list()
    mfe_vals = df["mfe"].to_list()

    # Determine outcome for coloring
    pnl_vals = df["pnl"].to_list() if "pnl" in df.columns else [0] * len(mae_vals)
    colors = [config.color_winner if p > 0 else config.color_loser for p in pnl_vals]

    fig = go.Figure()

    fig.add_trace(
        go.Scatter(
            x=mae_vals,
            y=mfe_vals,
            mode="markers",
            marker=dict(color=colors, size=8, opacity=0.6),
            name="Trades",
        )
    )

    # Add quantile lines
    quantiles = calculate_mae_mfe_quantiles(df)

    # MAE Q1, Q3 vertical lines
    fig.add_vline(x=quantiles.mae.q1, line_dash="dash", line_color="blue", annotation_text="MAE Q1")
    fig.add_vline(x=quantiles.mae.q3, line_dash="dash", line_color="blue", annotation_text="MAE Q3")

    # MFE Q1, Q3 horizontal lines
    fig.add_hline(
        y=quantiles.mfe.q1, line_dash="dash", line_color="green", annotation_text="MFE Q1"
    )
    fig.add_hline(
        y=quantiles.mfe.q3, line_dash="dash", line_color="green", annotation_text="MFE Q3"
    )

    # Equal scale
    if equal_scale:
        max_val = max(max(mae_vals), max(mfe_vals)) * 1.1
        fig.update_xaxes(range=[0, max_val])
        fig.update_yaxes(range=[0, max_val])
        # Add diagonal line
        fig.add_trace(
            go.Scatter(
                x=[0, max_val],
                y=[0, max_val],
                mode="lines",
                line=dict(color="gray", dash="dot"),
                name="MAE=MFE",
                showlegend=True,
            )
        )

    fig.update_layout(
        title="B1: MAE vs MFE (Entry Timing Analysis)",
        xaxis_title="MAE (Maximum Adverse Excursion)",
        yaxis_title="MFE (Maximum Favorable Excursion)",
        template=config.theme,
        width=config.width,
        height=config.height,
    )

    return fig


def analyze_entry_delay(df: pl.DataFrame) -> EntryDelayRecommendation:
    """B2-B5: Analyze whether entry delay is recommended.

    Returns recommendation based on MAE/MFE distribution.
    """
    quantiles = calculate_mae_mfe_quantiles(df)

    # Upper-right corner analysis (B2)
    # Use Q3 as upper-right reference
    mae_q3 = quantiles.mae.q3
    mfe_q3 = quantiles.mfe.q3

    # Calculate ratio
    if mfe_q3 > 0:
        mae_mfe_ratio = mae_q3 / mfe_q3
    else:
        mae_mfe_ratio = float("inf")

    # Determine if delay is needed
    should_delay = mae_mfe_ratio > 1.0  # MAE > MFE at upper-right

    # Calculate delay prices (B3)
    delay_price = quantiles.mae.q1 if should_delay else None
    delay_price_conservative = quantiles.mae.q1_q2_mid if should_delay else None

    # Generate reason
    if mae_mfe_ratio > 2.0:
        reason = "Strong delay recommended: MAE significantly exceeds MFE at upper-right (L-shape distribution)"
    elif mae_mfe_ratio > 1.0:
        reason = "Moderate delay recommended: MAE exceeds MFE, consider waiting for better entry"
    elif mae_mfe_ratio > 0.5:
        reason = "Optional delay: MAE and MFE relatively balanced"
    else:
        reason = "No delay needed: MFE dominates, enter immediately"

    return EntryDelayRecommendation(
        should_delay=should_delay,
        delay_price=delay_price,
        delay_price_conservative=delay_price_conservative,
        reason=reason,
        mae_mfe_ratio=mae_mfe_ratio,
    )


def entry_delay_visualization(
    df: pl.DataFrame,
    config: ChartConfig,
) -> go.Figure:
    """B2-B4: Visualize entry delay analysis with quadrant highlights.

    Shows:
    - MAE/MFE scatter
    - Quadrant analysis for delay decision
    - Recommended delay zones
    """
    go, make_subplots = _import_plotly()

    quantiles = calculate_mae_mfe_quantiles(df)
    recommendation = analyze_entry_delay(df)

    fig = make_subplots(
        rows=1,
        cols=2,
        subplot_titles=(
            "MAE/MFE Distribution with Delay Zones",
            "Entry Delay Impact Histogram",
        ),
    )

    mae_vals = df["mae"].to_list()
    mfe_vals = df["mfe"].to_list()
    pnl_vals = df["pnl"].to_list() if "pnl" in df.columns else [0] * len(mae_vals)
    colors = [config.color_winner if p > 0 else config.color_loser for p in pnl_vals]

    # Scatter plot
    fig.add_trace(
        go.Scatter(
            x=mae_vals,
            y=mfe_vals,
            mode="markers",
            marker=dict(color=colors, size=6, opacity=0.6),
            name="Trades",
        ),
        row=1,
        col=1,
    )

    # Add delay zone (if recommended)
    if recommendation.should_delay and recommendation.delay_price:
        # Shade the delay zone
        fig.add_vrect(
            x0=0,
            x1=recommendation.delay_price,
            fillcolor="rgba(0, 255, 0, 0.1)",
            layer="below",
            line_width=0,
            row=1,
            col=1,
        )
        fig.add_vline(
            x=recommendation.delay_price,
            line_dash="dash",
            line_color="green",
            annotation_text=f"Delay: {recommendation.delay_price:.4f}",
            row=1,
            col=1,
        )

    # MAE histogram showing potential improvement from delay
    fig.add_trace(
        go.Histogram(
            x=mae_vals,
            name="MAE Distribution",
            marker_color=config.color_loser,
            opacity=0.7,
            nbinsx=30,
        ),
        row=1,
        col=2,
    )

    if recommendation.delay_price:
        fig.add_vline(
            x=recommendation.delay_price,
            line_dash="dash",
            line_color="green",
            annotation_text="Delay Price",
            row=1,
            col=2,
        )

    fig.update_layout(
        title=f"Entry Delay Analysis - {recommendation.reason}",
        template=config.theme,
        width=config.width,
        height=config.height,
    )

    return fig


# =============================================================================
# Step C: Stop Loss / Take Profit Analysis
# =============================================================================


def analyze_sltp(
    df: pl.DataFrame,
    use_g_mfe: bool = False,
) -> SLTPRecommendation:
    """C1-C6: Analyze and recommend SL/TP levels.

    Args:
        df: Trades DataFrame.
        use_g_mfe: If True, use MFE before MAE for TP (wave trading).
                   If False, use MFE for TP (trend trading).

    Returns:
        SL/TP recommendation.
    """
    quantiles = calculate_mae_mfe_quantiles(df)

    # Basic SL from MAE distribution
    sl_raw = quantiles.mae.q3  # Cover 75% of adverse moves

    # TP from MFE (or g_mfe for wave trading)
    if use_g_mfe and quantiles.g_mfe:
        tp_raw = quantiles.g_mfe.q2  # Median of MFE before MAE
    else:
        tp_raw = quantiles.mfe.q2  # Median MFE

    # ATR-normalized if volatility columns exist
    sl_atr = None
    tp_atr = None
    if "mae_volatility" in df.columns:
        mae_atr = df.select((pl.col("mae") / pl.col("mae_volatility")).mean()).item()
        sl_atr = mae_atr * 1.5  # 1.5x average MAE in ATR

    if "mfe_volatility" in df.columns:
        mfe_col = "g_mfe" if use_g_mfe and "g_mfe" in df.columns else "mfe"
        vol_col = (
            "g_mfe_volatility"
            if use_g_mfe and "g_mfe_volatility" in df.columns
            else "mfe_volatility"
        )
        if vol_col in df.columns:
            mfe_atr = df.select((pl.col(mfe_col) / pl.col(vol_col)).mean()).item()
            tp_atr = mfe_atr

    # Cluster-based analysis (upper-right corner)
    # Use Q3 for both as cluster boundary
    cluster_sl = quantiles.mae.q3
    cluster_tp = (
        quantiles.mfe.q3
        if not use_g_mfe
        else (quantiles.g_mfe.q3 if quantiles.g_mfe else quantiles.mfe.q3)
    )

    # Risk/Reward
    risk_reward_ratio = tp_raw / sl_raw if sl_raw > 0 else 0

    # Expected win rate for breakeven
    # breakeven_wr = SL / (SL + TP)
    expected_wr = sl_raw / (sl_raw + tp_raw) if (sl_raw + tp_raw) > 0 else 0.5

    return SLTPRecommendation(
        sl_raw=sl_raw,
        tp_raw=tp_raw,
        sl_atr=sl_atr,
        tp_atr=tp_atr,
        cluster_sl=cluster_sl,
        cluster_tp=cluster_tp,
        risk_reward_ratio=risk_reward_ratio,
        expected_win_rate_for_breakeven=expected_wr,
    )


def sltp_quadrant_chart(
    df: pl.DataFrame,
    config: ChartConfig,
    use_g_mfe: bool = False,
) -> go.Figure:
    """C2-C3: Quadrant analysis for SL/TP placement.

    Shows cluster boundaries and recommended SL/TP zones.
    """
    go, _ = _import_plotly()

    recommendation = analyze_sltp(df, use_g_mfe=use_g_mfe)
    quantiles = calculate_mae_mfe_quantiles(df)

    mae_vals = df["mae"].to_list()
    mfe_col = "g_mfe" if use_g_mfe and "g_mfe" in df.columns else "mfe"
    mfe_vals = df[mfe_col].to_list()
    pnl_vals = df["pnl"].to_list() if "pnl" in df.columns else [0] * len(mae_vals)
    colors = [config.color_winner if p > 0 else config.color_loser for p in pnl_vals]

    fig = go.Figure()

    # Scatter
    fig.add_trace(
        go.Scatter(
            x=mae_vals,
            y=mfe_vals,
            mode="markers",
            marker=dict(color=colors, size=8, opacity=0.6),
            name="Trades",
        )
    )

    # SL zone (MAE Q3)
    fig.add_vline(
        x=recommendation.sl_raw,
        line_dash="solid",
        line_color=config.color_loser,
        annotation_text=f"SL: {recommendation.sl_raw:.4f}",
    )

    # TP zone (MFE median)
    fig.add_hline(
        y=recommendation.tp_raw,
        line_dash="solid",
        line_color=config.color_winner,
        annotation_text=f"TP: {recommendation.tp_raw:.4f}",
    )

    # Cluster boundary (upper-right)
    fig.add_vrect(
        x0=recommendation.cluster_sl,
        x1=max(mae_vals) * 1.1,
        fillcolor="rgba(255, 0, 0, 0.1)",
        layer="below",
        line_width=0,
        annotation_text="High Risk Zone",
    )

    fig.add_hrect(
        y0=recommendation.cluster_tp,
        y1=max(mfe_vals) * 1.1,
        fillcolor="rgba(0, 255, 0, 0.1)",
        layer="below",
        line_width=0,
        annotation_text="High Reward Zone",
    )

    mfe_label = "MFE before MAE" if use_g_mfe else "MFE"
    fig.update_layout(
        title=f"SL/TP Quadrant Analysis (R:R = {recommendation.risk_reward_ratio:.2f})",
        xaxis_title="MAE",
        yaxis_title=mfe_label,
        template=config.theme,
        width=config.width,
        height=config.height,
    )

    return fig


# =============================================================================
# Step D: Trailing Stop / Breakeven Analysis
# =============================================================================


def analyze_trailing_stop(df: pl.DataFrame) -> TrailingStopRecommendation:
    """D1-D3: Analyze trailing stop and breakeven levels."""
    # Split by outcome
    losers = df.filter(pl.col("pnl") <= 0)
    winners = df.filter(pl.col("pnl") > 0)

    # D2: Breakeven trigger from lose trade MFE
    if len(losers) > 0 and "mfe" in losers.columns:
        lose_mfe_stats = calculate_quantiles(losers["mfe"])
        breakeven_q1_q2 = lose_mfe_stats.q1_q2_mid
        breakeven_q2 = lose_mfe_stats.q2
    else:
        breakeven_q1_q2 = 0.0
        breakeven_q2 = 0.0

    # D3: Trailing distance from MHL
    if "mhl" in df.columns:
        mhl_stats = calculate_quantiles(df["mhl"])
        trailing_q2 = mhl_stats.q2
        trailing_q3 = mhl_stats.q3
    else:
        # Fallback to MAE if MHL not available
        if "mae" in df.columns:
            mae_stats = calculate_quantiles(df["mae"])
            trailing_q2 = mae_stats.q2
            trailing_q3 = mae_stats.q3
        else:
            trailing_q2 = 0.0
            trailing_q3 = 0.0

    # Check for inverse relationship (suitable for trailing)
    has_inverse = False
    if "mae" in df.columns and "mfe" in df.columns:
        # Calculate correlation
        corr = df.select(pl.corr("mae", "mfe")).item()
        has_inverse = corr is not None and corr < -0.3

    return TrailingStopRecommendation(
        breakeven_trigger_q1_q2=breakeven_q1_q2,
        breakeven_trigger_q2=breakeven_q2,
        trailing_distance_q2=trailing_q2,
        trailing_distance_q3=trailing_q3,
        has_inverse_relationship=has_inverse,
    )


def trailing_stop_chart(
    df: pl.DataFrame,
    config: ChartConfig,
) -> go.Figure:
    """D2-D3: Visualize trailing stop analysis."""
    go, make_subplots = _import_plotly()

    recommendation = analyze_trailing_stop(df)

    losers = df.filter(pl.col("pnl") <= 0)
    winners = df.filter(pl.col("pnl") > 0)

    fig = make_subplots(
        rows=1,
        cols=2,
        subplot_titles=(
            "D2: Lose Trade MFE (Breakeven Trigger)",
            "D3: MHL Distribution (Trailing Distance)",
        ),
    )

    # Lose trade MFE histogram
    if len(losers) > 0 and "mfe" in losers.columns:
        fig.add_trace(
            go.Histogram(
                x=losers["mfe"].to_list(),
                name="Lose Trade MFE",
                marker_color=config.color_loser,
                opacity=0.7,
                nbinsx=30,
            ),
            row=1,
            col=1,
        )
        # Add trigger lines
        fig.add_vline(
            x=recommendation.breakeven_trigger_q1_q2,
            line_dash="dash",
            line_color="orange",
            annotation_text="BE Trigger (Q1+Q2)/2",
            row=1,
            col=1,
        )
        fig.add_vline(
            x=recommendation.breakeven_trigger_q2,
            line_dash="solid",
            line_color="orange",
            annotation_text="BE Trigger Q2",
            row=1,
            col=1,
        )

    # MHL histogram
    mhl_col = "mhl" if "mhl" in df.columns else "mae"
    if mhl_col in df.columns:
        fig.add_trace(
            go.Histogram(
                x=df[mhl_col].to_list(),
                name=f"{mhl_col.upper()} Distribution",
                marker_color=config.color_neutral,
                opacity=0.7,
                nbinsx=30,
            ),
            row=1,
            col=2,
        )
        # Add trailing distance lines
        fig.add_vline(
            x=recommendation.trailing_distance_q2,
            line_dash="dash",
            line_color="purple",
            annotation_text="Trail Distance Q2",
            row=1,
            col=2,
        )
        fig.add_vline(
            x=recommendation.trailing_distance_q3,
            line_dash="solid",
            line_color="purple",
            annotation_text="Trail Distance Q3",
            row=1,
            col=2,
        )

    inverse_note = (
        "✓ Inverse relationship detected"
        if recommendation.has_inverse_relationship
        else "✗ No inverse relationship"
    )
    fig.update_layout(
        title=f"Trailing Stop Analysis - {inverse_note}",
        template=config.theme,
        width=config.width,
        height=config.height,
    )

    return fig


# =============================================================================
# Step E: Position Sizing Analysis
# =============================================================================


def analyze_position_sizing(
    df: pl.DataFrame,
    tp_level: float | None = None,
) -> PositionSizingRecommendation:
    """E1-E3: Analyze position sizing (add/reduce) levels."""
    winners = df.filter(pl.col("pnl") > 0)
    losers = df.filter(pl.col("pnl") <= 0)

    # E1: Adverse direction add (from Win Trade MAE)
    if len(winners) > 0 and "mae" in winners.columns:
        win_mae_stats = calculate_quantiles(winners["mae"])
        adverse_add_start = win_mae_stats.q1
        adverse_add_end = win_mae_stats.q2
        adverse_reduce = win_mae_stats.q2_q3_mid
    else:
        adverse_add_start = 0.0
        adverse_add_end = 0.0
        adverse_reduce = 0.0

    # E2: Favorable direction add (from Win Trade MFE)
    if len(winners) > 0 and "mfe" in winners.columns:
        win_mfe_stats = calculate_quantiles(winners["mfe"])
        favorable_add_start = win_mfe_stats.q2
        favorable_add_end = win_mfe_stats.q3
    else:
        favorable_add_start = 0.0
        favorable_add_end = 0.0

    # Crossover point (where Win MFE and Lose MFE CDFs cross)
    crossover = None
    if len(winners) > 0 and len(losers) > 0 and "mfe" in df.columns:
        win_mfe_median = winners["mfe"].median()
        lose_mfe_median = losers["mfe"].median()
        # Simple approximation: midpoint
        crossover = (win_mfe_median + lose_mfe_median) / 2

    # E3: Reduce zone (1/2 to 1/3 between add and TP)
    if tp_level and favorable_add_end > 0:
        reduce_zone = favorable_add_end + (tp_level - favorable_add_end) / 3
    else:
        reduce_zone = favorable_add_end * 1.2 if favorable_add_end > 0 else 0.0

    return PositionSizingRecommendation(
        adverse_add_zone_start=adverse_add_start,
        adverse_add_zone_end=adverse_add_end,
        adverse_reduce_zone=adverse_reduce,
        favorable_add_zone_start=favorable_add_start,
        favorable_add_zone_end=favorable_add_end,
        favorable_crossover_point=crossover,
        reduce_zone=reduce_zone,
    )


def position_sizing_chart(
    df: pl.DataFrame,
    config: ChartConfig,
) -> go.Figure:
    """E1-E3: Visualize position sizing analysis."""
    go, make_subplots = _import_plotly()

    recommendation = analyze_position_sizing(df)

    winners = df.filter(pl.col("pnl") > 0)
    losers = df.filter(pl.col("pnl") <= 0)

    fig = make_subplots(
        rows=1,
        cols=2,
        subplot_titles=(
            "E1: Win Trade MAE (Adverse Add Zone)",
            "E2: Win/Lose Trade MFE (Favorable Add Zone)",
        ),
    )

    # Win MAE histogram
    if len(winners) > 0 and "mae" in winners.columns:
        fig.add_trace(
            go.Histogram(
                x=winners["mae"].to_list(),
                name="Win Trade MAE",
                marker_color=config.color_winner,
                opacity=0.7,
                nbinsx=30,
            ),
            row=1,
            col=1,
        )
        # Add zones
        fig.add_vrect(
            x0=recommendation.adverse_add_zone_start,
            x1=recommendation.adverse_add_zone_end,
            fillcolor="rgba(0, 255, 0, 0.2)",
            layer="below",
            line_width=0,
            annotation_text="Add Zone",
            row=1,
            col=1,
        )

    # Win/Lose MFE comparison
    if "mfe" in df.columns:
        if len(winners) > 0:
            fig.add_trace(
                go.Histogram(
                    x=winners["mfe"].to_list(),
                    name="Win Trade MFE",
                    marker_color=config.color_winner,
                    opacity=0.5,
                    nbinsx=30,
                ),
                row=1,
                col=2,
            )
        if len(losers) > 0:
            fig.add_trace(
                go.Histogram(
                    x=losers["mfe"].to_list(),
                    name="Lose Trade MFE",
                    marker_color=config.color_loser,
                    opacity=0.5,
                    nbinsx=30,
                ),
                row=1,
                col=2,
            )
        # Add favorable zone
        fig.add_vrect(
            x0=recommendation.favorable_add_zone_start,
            x1=recommendation.favorable_add_zone_end,
            fillcolor="rgba(0, 0, 255, 0.1)",
            layer="below",
            line_width=0,
            annotation_text="Favorable Add",
            row=1,
            col=2,
        )
        # Crossover point
        if recommendation.favorable_crossover_point:
            fig.add_vline(
                x=recommendation.favorable_crossover_point,
                line_dash="dash",
                line_color="purple",
                annotation_text="Crossover",
                row=1,
                col=2,
            )

    fig.update_layout(
        title="Position Sizing Analysis (Step E)",
        template=config.theme,
        width=config.width,
        height=config.height,
        barmode="overlay",
    )

    return fig


# =============================================================================
# Complete Workflow Dashboard
# =============================================================================


def workflow_dashboard(
    df: pl.DataFrame,
    config: ChartConfig,
) -> go.Figure:
    """Generate complete 5-step workflow dashboard."""
    go, make_subplots = _import_plotly()

    fig = make_subplots(
        rows=3,
        cols=2,
        subplot_titles=(
            "A: MAE/MFE Time Series",
            "B: Entry Timing (MAE vs MFE)",
            "C: SL/TP Quadrant",
            "D: Trailing Stop Analysis",
            "E: Position Sizing",
            "Summary Statistics",
        ),
        specs=[
            [{"type": "scatter"}, {"type": "scatter"}],
            [{"type": "scatter"}, {"type": "histogram"}],
            [{"type": "histogram"}, {"type": "table"}],
        ],
        vertical_spacing=0.12,
        horizontal_spacing=0.08,
    )

    # Colors
    pnl_vals = df["pnl"].to_list() if "pnl" in df.columns else [0] * len(df)
    colors = [config.color_winner if p > 0 else config.color_loser for p in pnl_vals]

    # A: Time series (simplified - just show MAE and MFE)
    if "exit_time" in df.columns:
        sorted_df = df.sort("exit_time")
        times = list(range(len(sorted_df)))
        if "mae" in sorted_df.columns:
            fig.add_trace(
                go.Scatter(
                    x=times,
                    y=sorted_df["mae"].to_list(),
                    mode="lines",
                    name="MAE",
                    line=dict(color=config.color_loser),
                ),
                row=1,
                col=1,
            )
        if "mfe" in sorted_df.columns:
            fig.add_trace(
                go.Scatter(
                    x=times,
                    y=sorted_df["mfe"].to_list(),
                    mode="lines",
                    name="MFE",
                    line=dict(color=config.color_winner),
                ),
                row=1,
                col=1,
            )

    # B: Entry timing scatter
    if "mae" in df.columns and "mfe" in df.columns:
        fig.add_trace(
            go.Scatter(
                x=df["mae"].to_list(),
                y=df["mfe"].to_list(),
                mode="markers",
                marker=dict(color=colors, size=5, opacity=0.5),
                name="Trades",
                showlegend=False,
            ),
            row=1,
            col=2,
        )

    # C: SL/TP scatter (same as B but with annotations)
    if "mae" in df.columns and "mfe" in df.columns:
        sltp = analyze_sltp(df)
        fig.add_trace(
            go.Scatter(
                x=df["mae"].to_list(),
                y=df["mfe"].to_list(),
                mode="markers",
                marker=dict(color=colors, size=5, opacity=0.5),
                showlegend=False,
            ),
            row=2,
            col=1,
        )
        fig.add_vline(x=sltp.sl_raw, line_dash="dash", line_color=config.color_loser, row=2, col=1)
        fig.add_hline(y=sltp.tp_raw, line_dash="dash", line_color=config.color_winner, row=2, col=1)

    # D: MHL or MAE histogram for trailing
    mhl_col = "mhl" if "mhl" in df.columns else "mae"
    if mhl_col in df.columns:
        fig.add_trace(
            go.Histogram(
                x=df[mhl_col].to_list(),
                marker_color=config.color_neutral,
                opacity=0.7,
                nbinsx=30,
                showlegend=False,
            ),
            row=2,
            col=2,
        )

    # E: Win/Lose MFE
    if "mfe" in df.columns:
        winners = df.filter(pl.col("pnl") > 0)
        losers = df.filter(pl.col("pnl") <= 0)
        if len(winners) > 0:
            fig.add_trace(
                go.Histogram(
                    x=winners["mfe"].to_list(),
                    marker_color=config.color_winner,
                    opacity=0.5,
                    nbinsx=30,
                    name="Win MFE",
                ),
                row=3,
                col=1,
            )
        if len(losers) > 0:
            fig.add_trace(
                go.Histogram(
                    x=losers["mfe"].to_list(),
                    marker_color=config.color_loser,
                    opacity=0.5,
                    nbinsx=30,
                    name="Lose MFE",
                ),
                row=3,
                col=1,
            )

    # Summary table
    quantiles = calculate_mae_mfe_quantiles(df)
    sltp = analyze_sltp(df)
    trailing = analyze_trailing_stop(df)
    sizing = analyze_position_sizing(df)

    summary_data = [
        ["Metric", "Value"],
        ["MAE Q2", f"{quantiles.mae.q2:.4f}"],
        ["MFE Q2", f"{quantiles.mfe.q2:.4f}"],
        ["Suggested SL", f"{sltp.sl_raw:.4f}"],
        ["Suggested TP", f"{sltp.tp_raw:.4f}"],
        ["R:R Ratio", f"{sltp.risk_reward_ratio:.2f}"],
        ["BE Trigger", f"{trailing.breakeven_trigger_q2:.4f}"],
        ["Trail Distance", f"{trailing.trailing_distance_q2:.4f}"],
        ["Add Zone Start", f"{sizing.favorable_add_zone_start:.4f}"],
    ]

    fig.add_trace(
        go.Table(
            header=dict(values=summary_data[0], fill_color="paleturquoise", align="left"),
            cells=dict(values=list(zip(*summary_data[1:])), fill_color="lavender", align="left"),
        ),
        row=3,
        col=2,
    )

    fig.update_layout(
        title="MAE/MFE 5-Step Workflow Dashboard",
        template=config.theme,
        width=config.width * 1.5,
        height=config.height * 2,
        showlegend=True,
        barmode="overlay",
    )

    return fig
