import numpy as np
import pandas as pd

from strategies.mlp_tail_event_research import (
    TailRule,
    moving_block_bootstrap_matched_lift,
    relative_tail_labels,
    tail_classifier_metrics,
    volatility_matched_downside_profile,
)


def test_relative_tail_labels_mark_both_tails():
    frame = pd.DataFrame({"forward_return": [-0.5, -0.1, 0.0, 0.1, 0.5]})

    assert relative_tail_labels(frame, 0.20).tolist() == [-1, 0, 0, 0, 1]


def test_volatility_matched_profile_detects_incremental_downside_rate():
    rows = []
    for year in (2023, 2024):
        for index in range(20):
            selected = index < 5
            rows.append({
                "time": pd.Timestamp(f"{year}-01-01") + pd.Timedelta(hours=6 * index),
                "forward_return": -0.20 if selected else 0.01,
                "signal": -1.0 if selected else 1.0,
                "rvol_norm": index / 20,
            })
    frame = pd.DataFrame(rows)

    profile = volatility_matched_downside_profile(frame, TailRule("signal", "low", 0.0), tail_fraction=0.20, bins=2)

    assert profile["selected"] == 10
    assert profile["delta"] is not None and profile["delta"] > 0.0


def test_tail_classifier_handles_nonfinite_feature_values():
    values = np.tile(np.arange(10, dtype=float), 8)
    frame = pd.DataFrame({"signal": values, "forward_return": np.where(values < 2, -0.2, np.where(values > 7, 0.2, 0.0))})
    frame.loc[0, "signal"] = np.inf

    metrics = tail_classifier_metrics(frame.iloc[:50], frame.iloc[50:], features=["signal"], tail_fraction=0.10)

    assert metrics["observations"] == 30
    assert metrics["down_pr_auc"] >= metrics["tail_base_rate"]


def test_moving_block_bootstrap_is_deterministic_and_retains_signal():
    rows = []
    for index in range(120):
        selected = index % 12 < 3
        rows.append({
            "time": pd.Timestamp("2024-01-01") + pd.Timedelta(hours=6 * index),
            "forward_return": -0.2 if selected else (-0.4 if index % 20 == 7 else 0.01),
            "signal": -1.0 if selected else 1.0,
            "rvol_norm": (index % 10) / 10,
        })
    frame = pd.DataFrame(rows)

    first = moving_block_bootstrap_matched_lift(frame, TailRule("signal", "low", 0.0), tail_fraction=0.10, repetitions=30, seed=3)
    second = moving_block_bootstrap_matched_lift(frame, TailRule("signal", "low", 0.0), tail_fraction=0.10, repetitions=30, seed=3)

    assert first == second
    assert first["share_above_one"] == 1.0
