import numpy as np
import pandas as pd
import pytest

import tools.run_mlp_score_peak_event_study as study


def test_confirmed_pivots_are_not_available_before_right_confirmation():
    scores = np.array([0.0, 100.0, 500.0, 100.0, 0.0])
    pivots = study.confirmed_pivot_highs(scores, left=2, right=2)

    assert pivots == [(2, 4, 500.0)]


def test_event_rules_enforce_thresholds_spacing_and_deduplication():
    pivots = [
        (2, 4, 500.0),
        (7, 11, 250.0),                  # only 7 bars after first: invalid
        (10, 12, 250.0),                 # valid, event confirmation=12
        (16, 18, 200.0),                  # overlapping candidate; deduped
        (30, 32, 250.0),                  # next non-overlapping valid event
        # This cannot qualify: the closest preceding 250 peak is below the
        # first-peak threshold and the 500 peak is more than 40 bars away.
        (46, 48, 100.0),
    ]

    events = study.detect_deterioration_events(pivots, horizon=14)

    assert [event["event_index"] for event in events] == [12, 32]
    assert events[0]["first_score"] == 500.0
    assert events[0]["second_score"] == 250.0


def test_dedup_allows_the_first_event_after_the_inclusive_horizon():
    pivots = [
        (2, 4, 500.0),
        (10, 12, 250.0),  # first event
        (24, 26, 200.0),  # exactly 14 bars later: still excluded
        (25, 27, 200.0),  # first eligible timestamp after the horizon
    ]

    events = study.detect_deterioration_events(pivots, horizon=14)

    assert [event["event_index"] for event in events] == [12, 27]


def test_forward_returns_and_mae_are_close_to_close_and_capped_at_horizon():
    closes = np.array([100.0, 100.0, 100.0, 100.0, 110.0, 90.0, 120.0])
    metrics = study.forward_metrics(closes, event_index=3, horizons=(1, 3))

    assert metrics[1]["return_pct"] == pytest.approx(10.0)
    assert metrics[1]["mae_pct"] == pytest.approx(0.0)
    assert metrics[3]["return_pct"] == pytest.approx(20.0)
    assert metrics[3]["mae_pct"] == pytest.approx(-10.0)


def test_controls_are_score_matched_same_region_and_exclude_event_horizons():
    times = pd.date_range("2024-01-01", periods=30, freq="6h")
    frame = pd.DataFrame({"time": times, "activation_score": np.full(30, 200.0)})
    events = [{"event_index": 10, "event_score": 200.0}]

    controls = study.match_controls(frame, events, horizon=3, score_band=50.0, region_days=30)

    assert len(controls) == 1
    assert controls[0] not in {10, 11, 12, 13}
    assert abs(frame.loc[controls[0], "activation_score"] - 200.0) <= 50.0
