"""Test fixtures for Trades analysis tests."""

from __future__ import annotations

from datetime import datetime, timedelta

import numpy as np
import polars as pl
import pytest


@pytest.fixture
def sample_trades_df() -> pl.DataFrame:
    """Generate sample trades DataFrame with full column set.

    Creates 100 trades with realistic patterns including:
    - Exit/entry reasons
    - Advanced trigger flags
    - Strategy/blueprint names
    - Time columns
    - MAE/MFE with volatility
    """
    np.random.seed(42)
    n_trades = 100

    # Generate trade parameters
    directions = np.random.choice([1, -1], size=n_trades)
    entry_prices = np.random.uniform(100, 110, size=n_trades)

    # Generate MAE/MFE with some realistic correlation to PnL
    mae = np.abs(np.random.exponential(2.0, size=n_trades))
    mfe = np.abs(np.random.exponential(3.0, size=n_trades))

    # Calculate PnL based on direction and excursions
    pnl = (mfe - mae) * directions + np.random.normal(0, 0.5, size=n_trades)
    pnl_pct = pnl / entry_prices * 100

    # Additional metrics
    g_mfe = mfe * np.random.uniform(1.0, 1.2, size=n_trades)
    mae_lv1 = mae * np.random.uniform(0.3, 0.7, size=n_trades)
    mhl = mfe + mae

    # Index columns
    mae_idx = np.random.randint(1, 50, size=n_trades).astype(np.uint32)
    mfe_idx = np.random.randint(1, 50, size=n_trades).astype(np.uint32)
    g_mfe_idx = np.random.randint(1, 50, size=n_trades).astype(np.uint32)
    mae_lv1_idx = np.random.randint(1, 50, size=n_trades).astype(np.uint32)
    mhl_idx = np.random.randint(1, 50, size=n_trades).astype(np.uint32)

    # Volatility columns
    base_vol = np.random.uniform(0.5, 2.0, size=n_trades)
    entry_volatility = base_vol
    exit_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)
    mae_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)
    mfe_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)
    g_mfe_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)
    mae_lv1_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)
    mhl_volatility = base_vol * np.random.uniform(0.9, 1.1, size=n_trades)

    # Holding period
    holding_bars = np.random.randint(5, 200, size=n_trades).astype(np.uint32)
    holding_seconds = holding_bars * 60 * 15  # Assume 15-min bars

    # Entry/Exit reasons (matching Rust OrderStrategy enum)
    # Entry: 0=Immediate, 1=Favorable Delay, 2=Adverse Delay
    entry_reasons = np.random.choice([0, 1, 2], size=n_trades).astype(np.uint32)
    # Exit: 4=SL, 5=TP, 6=TrailingStop, 7=Breakeven, 8=Timeout
    exit_reasons = np.random.choice([4, 5, 6, 7, 8], size=n_trades).astype(np.uint32)

    # Advanced trigger flags
    is_adv_triggered = np.random.choice([True, False], size=n_trades)

    # Strategy/Blueprint names
    strategies = np.random.choice(["Strategy_A", "Strategy_B"], size=n_trades)
    blueprints = np.random.choice(["Blueprint_1", "Blueprint_2", "Blueprint_3"], size=n_trades)

    # Time columns
    base_time = datetime(2024, 1, 1)
    entry_times = [base_time + timedelta(hours=i * 4) for i in range(n_trades)]
    exit_times = [
        entry_times[i] + timedelta(minutes=int(holding_bars[i] * 15)) for i in range(n_trades)
    ]

    # Entry price hypotheticals
    favorable_entry_hypo = entry_prices * np.random.uniform(0.98, 1.0, size=n_trades)
    adverse_entry_hypo = entry_prices * np.random.uniform(1.0, 1.02, size=n_trades)

    # Exit price hypotheticals
    exit_prices = entry_prices + pnl
    favorable_exit_hypo = exit_prices * np.random.uniform(1.0, 1.02, size=n_trades)
    adverse_exit_hypo = exit_prices * np.random.uniform(0.98, 1.0, size=n_trades)

    return pl.DataFrame(
        {
            "direction": directions.astype(np.int32),
            "status": [False] * n_trades,  # All closed
            # Entry details
            "entry_idx": np.arange(n_trades).astype(np.uint32),
            "entry_time": entry_times,
            "entry_price": entry_prices,
            "entry_reason": entry_reasons,
            "favorable_entry_hypo_price": favorable_entry_hypo,
            "adverse_entry_hypo_price": adverse_entry_hypo,
            "favorable_entry_strategy": entry_reasons,
            "adverse_entry_strategy": entry_reasons,
            "neutral_entry_strategy": entry_reasons,
            # Exit details
            "exit_idx": (np.arange(n_trades) + holding_bars).astype(np.uint32),
            "exit_time": exit_times,
            "exit_price": exit_prices,
            "exit_reason": exit_reasons,
            "favorable_exit_hypo_price": favorable_exit_hypo,
            "adverse_exit_hypo_price": adverse_exit_hypo,
            "favorable_exit_strategy": exit_reasons,
            "adverse_exit_strategy": exit_reasons,
            "neutral_exit_strategy": exit_reasons,
            # Holding period
            "holding_bars": holding_bars,
            "holding_seconds": holding_seconds.astype(np.int64),
            # MAE/MFE metrics
            "mae": mae,
            "mfe": mfe,
            "g_mfe": g_mfe,
            "mae_lv1": mae_lv1,
            "mhl": mhl,
            # MAE/MFE indices
            "mae_idx": mae_idx,
            "mfe_idx": mfe_idx,
            "g_mfe_idx": g_mfe_idx,
            "mae_lv1_idx": mae_lv1_idx,
            "mhl_idx": mhl_idx,
            # Volatility
            "entry_volatility": entry_volatility,
            "exit_volatility": exit_volatility,
            "mae_volatility": mae_volatility,
            "mfe_volatility": mfe_volatility,
            "g_mfe_volatility": g_mfe_volatility,
            "mae_lv1_volatility": mae_lv1_volatility,
            "mhl_volatility": mhl_volatility,
            # Base layer entry info
            "base_entry_time": entry_times,
            "base_entry_price": entry_prices * 0.99,
            "is_adv_triggered": is_adv_triggered,
            # PnL
            "pnl": pnl,
            "pnl_pct": pnl_pct,
            # Strategy info
            "strategy_name": strategies,
            "blueprint_name": blueprints,
        }
    )


@pytest.fixture
def minimal_trades_df() -> pl.DataFrame:
    """Minimal trades DataFrame for testing.

    Contains only the required columns (direction, pnl) with 10 trades.
    """
    return pl.DataFrame(
        {
            "direction": [1, -1, 1, -1, 1, -1, 1, -1, 1, -1],
            "pnl": [1.0, -0.5, 2.0, -1.5, 0.5, -2.0, 1.5, -0.8, 3.0, -1.0],
        }
    )


@pytest.fixture
def empty_trades_df() -> pl.DataFrame:
    """Empty trades DataFrame for edge case testing."""
    return pl.DataFrame(
        {
            "direction": pl.Series([], dtype=pl.Int32),
            "pnl": pl.Series([], dtype=pl.Float64),
        }
    )


@pytest.fixture
def single_trade_df() -> pl.DataFrame:
    """Single trade DataFrame for edge case testing."""
    return pl.DataFrame(
        {
            "direction": [1],
            "pnl": [1.0],
            "mae": [0.5],
            "mfe": [2.0],
            "exit_reason": [5],  # Take Profit
            "entry_reason": [0],  # Immediate
        }
    )


@pytest.fixture
def trades_with_exit_reasons() -> pl.DataFrame:
    """Trades DataFrame with various exit reasons."""
    return pl.DataFrame(
        {
            "direction": [1, -1, 1, -1, 1, 1, -1, 1, -1, 1],
            "pnl": [1.0, -0.5, 2.0, -1.5, 0.5, -2.0, 1.5, -0.8, 3.0, -1.0],
            "mae": [0.5, 1.0, 0.3, 2.0, 0.8, 3.0, 0.4, 1.5, 0.2, 1.2],
            "exit_reason": [4, 4, 5, 5, 6, 6, 7, 7, 8, 8],  # SL, TP, Trail, BE, Timeout
        }
    )


@pytest.fixture
def trades_with_entry_reasons() -> pl.DataFrame:
    """Trades DataFrame with various entry reasons."""
    return pl.DataFrame(
        {
            "direction": [1, -1, 1, -1, 1, 1],
            "pnl": [1.0, -0.5, 2.0, -1.5, 0.5, -0.2],
            "mae": [0.5, 1.0, 0.3, 2.0, 0.8, 0.9],
            "entry_reason": [0, 0, 1, 1, 2, 2],  # Immediate, Favorable, Adverse
        }
    )
