"""Execution sensitivity is different from raw-score proximity."""
import numpy as np
import pandas as pd

from strategies.strategy_mlp_scores import _score_to_signals
from tools.run_mlp_entry_loss_experiment import evaluator


def test_disabled_confirmation_can_be_flagged_without_changing_trades():
    module = evaluator()
    frame = pd.DataFrame(dict(activation_score=[200., 50., -260.01, 220., 40.],
                              close=[100., 101., 102., 101., 104.],
                              high=[100., 101., 102., 101., 104.]))
    params = dict(i_long_entry_activation_threshold=90.,
                  i_long_exit_activation_threshold=210.,
                  i_long_exit_activation_confirmation_threshold=-260.,
                  i_use_long_exit_confirmation=False, i_trailing_stop_threshold=20.)
    assert module.fragile_count(frame.activation_score, params, 0.05) == 1
    def replay(p):
        return _score_to_signals(frame.copy(), p, np.ones(5), frame.close.to_numpy(), frame.high.to_numpy())
    base = replay(params)
    for delta in (-1., -.05, .05, 1.):
        candidate = replay(dict(params, i_long_exit_activation_confirmation_threshold=-260.+delta))
        for key in ('position', 'execute_entry', 'execute_exit'):
            np.testing.assert_array_equal(base[key], candidate[key])


def test_sample_is_balanced_deterministic_and_deduplicated():
    from tools.run_mlp_revisit import select_centers
    rows = [dict(mlp_weights_file=model, x=i, **{'Fragile_0.05': i % 2})
            for model in ('a', 'b') for i in range(30)]
    selected = select_centers(rows, [rows[0]], ['mlp_weights_file', 'x'])
    assert selected == select_centers(rows, [rows[0]], ['mlp_weights_file', 'x'])
    assert sum(x['sample'] for x in selected) == 40
    assert len({(x['params']['mlp_weights_file'], x['params']['x']) for x in selected}) == len(selected)


def test_gate_replay_is_prefix_causal_and_disabled_gate_is_identical():
    from tools.run_mlp_revisit import gate_signal
    rng = np.random.default_rng(12)
    frame = pd.DataFrame(dict(activation_score=rng.normal(0, 300, 150),
        close=np.exp(rng.normal(0, .03, 150).cumsum())*100))
    frame['high'] = frame.close * 1.01
    args = ({'i_trailing_stop_threshold': 5.}, np.zeros(150), frame.close.to_numpy(), frame.high.to_numpy())
    canonical = _score_to_signals(frame.copy(), *args)
    disabled = gate_signal(0)(frame.copy(), *args)
    for key in ('position', 'execute_entry', 'execute_exit'):
        np.testing.assert_array_equal(canonical[key], disabled[key])
    for width in (2, 3, 4):
        whole = gate_signal(width)(frame.copy(), *args)
        for end in (20, 57, 100):
            prefix = gate_signal(width)(frame.iloc[:end].copy(), args[0], args[1][:end], args[2][:end], args[3][:end])
            for key in ('position', 'execute_entry', 'execute_exit'):
                np.testing.assert_array_equal(whole[key].iloc[:end], prefix[key])
