import numpy as np
import pandas as pd
import pytest

from psx_signal.backtest import run_long_only_backtest
from psx_signal.config import BacktestConfig, CostConfig, SignalConfig
from psx_signal.predictions import probabilities_to_signals


def test_signal_thresholds_are_configurable() -> None:
    probabilities = np.array([[0.05, 0.10, 0.85], [0.60, 0.30, 0.10], [0.34, 0.33, 0.33]])
    assert probabilities_to_signals(probabilities, SignalConfig()) == ["STRONG BUY", "SELL", "HOLD"]


def test_backtest_applies_round_trip_costs_and_next_open_dates() -> None:
    predictions = pd.DataFrame({
        "symbol": ["AAA"], "execution_date": pd.to_datetime(["2026-01-02"]),
        "exit_date": pd.to_datetime(["2026-01-06"]), "forward_return": [0.10], "signal": ["BUY"],
    })
    metrics, trades = run_long_only_backtest(
        predictions,
        CostConfig(brokerage_bps=10, taxes_fees_bps=5, slippage_bps=5),
        BacktestConfig(position_fraction=1.0),
    )
    assert trades.iloc[0]["net_return"] == pytest.approx(0.096)
    assert metrics["total_return"] == pytest.approx(0.096)


def test_sell_signal_exits_existing_position_at_next_open() -> None:
    predictions = pd.DataFrame({
        "symbol": ["AAA", "AAA"],
        "execution_date": pd.to_datetime(["2026-01-02", "2026-01-05"]),
        "exit_date": pd.to_datetime(["2026-01-09", "2026-01-12"]),
        "entry_open": [100.0, 105.0], "exit_close": [120.0, 90.0],
        "forward_return": [0.20, -0.14], "signal": ["BUY", "SELL"],
    })
    _, trades = run_long_only_backtest(predictions, CostConfig(), BacktestConfig(position_fraction=1.0))
    assert len(trades) == 1
    assert trades.iloc[0]["exit_date"] == pd.Timestamp("2026-01-05")
    assert trades.iloc[0]["gross_return"] == pytest.approx(0.05)
    assert trades.iloc[0]["exit_reason"] == "SELL_SIGNAL"
