from __future__ import annotations

from crypto_spot_bot.analytics import risk_guard_snapshot
from crypto_spot_bot.data_quality import analyze_symbol_quality
from crypto_spot_bot.models import Candle, Ticker, Trade, utc_now
from crypto_spot_bot.storage import Storage


def test_risk_guard_reduces_size_after_consecutive_losses(make_settings, tmp_path) -> None:
    settings = make_settings(tmp_path, risk_max_consecutive_losses=2)
    storage = Storage(settings.database_path)
    now = utc_now()
    for _ in range(2):
        storage.insert_trade(
            Trade(
                id=None,
                symbol="BTCUSDT",
                side="SELL",
                qty=1.0,
                entry_price=100.0,
                exit_price=99.0,
                net_pnl=-1.0,
                opened_at=now,
                closed_at=now,
                entry_diagnostics={"forecast": {"probability_up": 0.64, "model": "torch_gru"}},
            )
        )

    guard = risk_guard_snapshot(settings, storage.closed_trades(), storage.latest_equity())

    assert guard["block_new_entries"] is False
    assert "consecutive_losses" in guard["reasons"]
    assert guard["position_size_multiplier"] == settings.risk_reduce_multiplier


def test_risk_guard_blocks_only_bad_symbol(make_settings, tmp_path) -> None:
    settings = make_settings(
        tmp_path,
        risk_symbol_guard_enabled=True,
        risk_max_consecutive_losses=3,
        symbols=["BTCUSDT", "ETHUSDT"],
    )
    storage = Storage(settings.database_path)
    now = utc_now()
    for _ in range(3):
        storage.insert_trade(
            Trade(
                id=None,
                symbol="BTCUSDT",
                side="SELL",
                qty=1.0,
                entry_price=100.0,
                exit_price=99.0,
                net_pnl=-1.0,
                opened_at=now,
                closed_at=now,
                entry_diagnostics={"forecast": {"probability_up": 0.64, "model": "torch_gru"}},
            )
        )
    storage.insert_trade(
        Trade(
            id=None,
            symbol="ETHUSDT",
            side="SELL",
            qty=1.0,
            entry_price=100.0,
            exit_price=102.0,
            net_pnl=2.0,
            opened_at=now,
            closed_at=now,
            entry_diagnostics={"forecast": {"probability_up": 0.64, "model": "torch_gru"}},
        )
    )

    guard = risk_guard_snapshot(settings, storage.closed_trades(), storage.latest_equity())

    assert guard["block_new_entries"] is False
    assert guard["blocked_symbols"] == ["BTCUSDT"]
    symbol_rows = {row["symbol"]: row for row in guard["symbols"]}
    assert symbol_rows["BTCUSDT"]["block_new_entries"] is True
    assert symbol_rows["ETHUSDT"]["block_new_entries"] is False


def test_risk_guard_can_disable_symbol_blocks(make_settings, tmp_path) -> None:
    settings = make_settings(
        tmp_path,
        risk_symbol_guard_enabled=False,
        risk_max_consecutive_losses=3,
        symbols=["BTCUSDT", "ETHUSDT"],
    )
    storage = Storage(settings.database_path)
    now = utc_now()
    for _ in range(3):
        storage.insert_trade(
            Trade(
                id=None,
                symbol="BTCUSDT",
                side="SELL",
                qty=1.0,
                entry_price=100.0,
                exit_price=99.0,
                net_pnl=-1.0,
                opened_at=now,
                closed_at=now,
                entry_diagnostics={"forecast": {"probability_up": 0.64, "model": "torch_gru"}},
            )
        )

    guard = risk_guard_snapshot(settings, storage.closed_trades(), storage.latest_equity())

    assert guard["symbol_guard_enabled"] is False
    assert guard["blocked_symbols"] == []
    symbol_rows = {row["symbol"]: row for row in guard["symbols"]}
    assert symbol_rows["BTCUSDT"]["consecutive_losses"] == 3
    assert symbol_rows["BTCUSDT"]["block_new_entries"] is False
    assert symbol_rows["BTCUSDT"]["reasons"] == []


def test_risk_guard_ignores_trades_outside_active_universe(make_settings, tmp_path) -> None:
    settings = make_settings(tmp_path, risk_max_consecutive_losses=2, symbols=["BTCUSDT", "ETHUSDT"])
    storage = Storage(settings.database_path)
    now = utc_now()
    for _ in range(4):
        storage.insert_trade(
            Trade(
                id=None,
                symbol="HYPEUSDT",
                side="SELL",
                qty=1.0,
                entry_price=100.0,
                exit_price=99.0,
                net_pnl=-1.0,
                opened_at=now,
                closed_at=now,
            )
        )

    guard = risk_guard_snapshot(settings, storage.closed_trades(), storage.latest_equity())

    assert guard["block_new_entries"] is False
    assert guard["reasons"] == []
    assert guard["blocked_symbols"] == []


def test_data_quality_flags_missing_candle_gap() -> None:
    candles = [
        Candle(1_000_000, 100, 101, 99, 100.5, 10),
        Candle(1_000_000 + 60 * 60 * 1000 * 3, 100.5, 102, 100, 101, 12),
    ]
    ticker = Ticker("BTCUSDT", 101, 100.99, 101.01, 1_000_000, 100, 0)

    row = analyze_symbol_quality(symbol="BTCUSDT", candles=candles, ticker=ticker, interval="60")

    assert row["status"] == "warn"
    assert any(issue["code"] == "missing_candles" for issue in row["issues"])
