from pathlib import Path

from config import BotConfig


def test_flash_crash_entry_signal_allows_qualified_dump():
    from strategy import should_enter_flash_crash

    cfg = BotConfig(flash_crash_trigger_pct=4.5, min_volume_24h=1_000, cooldown_minutes=60)
    history = [(1.0, 100.0), (2.0, 99.0), (3.0, 95.0)]

    decision = should_enter_flash_crash(
        coin="BTC",
        history=history,
        current_price=95.0,
        volume_24h=2_000,
        baseline_price=100.0,
        open_positions=set(),
        cooldowns={},
        now_ts=10_000.0,
        cfg=cfg,
    )

    assert decision.enter is True
    assert decision.reason == "flash_crash"
    assert decision.drop_pct <= -4.5


def test_flash_crash_entry_signal_blocks_recent_cooldown():
    from strategy import should_enter_flash_crash

    cfg = BotConfig(flash_crash_trigger_pct=4.5, min_volume_24h=1_000, cooldown_minutes=60)
    history = [(1.0, 100.0), (2.0, 95.0)]

    decision = should_enter_flash_crash(
        coin="BTC",
        history=history,
        current_price=95.0,
        volume_24h=2_000,
        baseline_price=100.0,
        open_positions=set(),
        cooldowns={"BTC": 9_900.0},
        now_ts=10_000.0,
        cfg=cfg,
    )

    assert decision.enter is False
    assert decision.reason == "cooldown"


def test_squeeze_breakout_entry_requires_compression_then_breakout():
    from strategy import should_enter_volatility_squeeze_breakout

    cfg = BotConfig(
        strategy_family="volatility_squeeze_breakout",
        squeeze_lookback_ticks=6,
        squeeze_max_band_width_pct=1.2,
        squeeze_breakout_pct=0.45,
        min_volume_24h=1_000,
    )
    compressed_then_breakout = [
        (1.0, 100.00),
        (2.0, 100.10),
        (3.0, 99.95),
        (4.0, 100.05),
        (5.0, 99.90),
        (6.0, 100.00),
    ]

    decision = should_enter_volatility_squeeze_breakout(
        coin="SOL",
        history=compressed_then_breakout,
        current_price=100.60,
        volume_24h=2_000,
        open_positions=set(),
        cooldowns={},
        now_ts=10_000.0,
        cfg=cfg,
    )

    assert decision.enter is True
    assert decision.reason == "squeeze_breakout"
    assert decision.drop_pct > 0
    assert decision.required_drop_pct == 0.45


def test_squeeze_breakout_blocks_wide_chop():
    from strategy import should_enter_volatility_squeeze_breakout

    cfg = BotConfig(
        strategy_family="volatility_squeeze_breakout",
        squeeze_lookback_ticks=6,
        squeeze_max_band_width_pct=1.2,
        squeeze_breakout_pct=0.45,
        min_volume_24h=1_000,
    )
    wide_chop = [(1.0, 100.0), (2.0, 103.0), (3.0, 97.5), (4.0, 102.0), (5.0, 98.5), (6.0, 100.0)]

    decision = should_enter_volatility_squeeze_breakout(
        coin="SOL",
        history=wide_chop,
        current_price=103.0,
        volume_24h=2_000,
        open_positions=set(),
        cooldowns={},
        now_ts=10_000.0,
        cfg=cfg,
    )

    assert decision.enter is False
    assert decision.reason == "not_compressed"


def test_exit_decision_closes_dead_fish_long_after_time_limit():
    from strategy import PositionState, exit_long_position

    cfg = BotConfig(dead_fish_time_limit_mins=15, max_hard_stop_pct=3.0)
    state = PositionState(entry_ts=0.0, high_px=100.0, atr_sl_px=97.0)

    decision = exit_long_position(entry_px=100.0, current_px=99.5, leverage=5, state=state, now_ts=16 * 60, cfg=cfg)

    assert decision.close is True
    assert decision.reason.startswith("Dead Fish")


def test_exit_decision_closes_long_on_hard_stop():
    from strategy import PositionState, exit_long_position

    cfg = BotConfig(dead_fish_time_limit_mins=15, max_hard_stop_pct=3.0)
    state = PositionState(entry_ts=0.0, high_px=100.0, atr_sl_px=80.0)

    decision = exit_long_position(entry_px=100.0, current_px=96.9, leverage=5, state=state, now_ts=60, cfg=cfg)

    assert decision.close is True
    assert "SL Hit" in decision.reason


def test_risk_blocks_when_kill_switch_file_exists(tmp_path):
    from risk import risk_gate

    kill_switch = tmp_path / "KILL_SWITCH"
    kill_switch.write_text("stop")

    result = risk_gate(daily_pnl_usd=0.0, daily_trade_count=0, kill_switch_path=kill_switch, cfg=BotConfig())

    assert result.allowed is False
    assert result.reason == "kill_switch"


def test_risk_blocks_daily_loss_limit():
    from risk import risk_gate

    cfg = BotConfig(max_daily_loss_usd=25.0)

    result = risk_gate(daily_pnl_usd=-25.01, daily_trade_count=0, kill_switch_path=Path("/tmp/not-present"), cfg=cfg)

    assert result.allowed is False
    assert result.reason == "daily_loss_limit"


def test_panic_guard_requires_exact_wallet_specific_confirmation():
    from panic_guard import expected_confirmation, validate_panic_confirmation

    wallet = "0x1234567890abcdef"
    expected = expected_confirmation(wallet)

    assert expected == "CLOSE ALL cdef"
    assert validate_panic_confirmation(expected, wallet) is True
    assert validate_panic_confirmation("CLOSE ALL", wallet) is False
    assert validate_panic_confirmation("CLOSE ALL beef", wallet) is False
