from decimal import Decimal

from binance_quant.auto_sell import AutoSellMarketSnapshot, AutoSellScanner
from binance_quant.models import Candle


def candle(index: int, open_price: str, close_price: str, volume: str = "10") -> Candle:
    return Candle(
        symbol="BTCUSDT",
        open_time=index,
        close_time=index + 1,
        open=Decimal(open_price),
        high=max(Decimal(open_price), Decimal(close_price)),
        low=min(Decimal(open_price), Decimal(close_price)),
        close=Decimal(close_price),
        volume=Decimal(volume),
    )


def test_auto_sell_scanner_selects_downside_candidate():
    snapshots = [
        AutoSellMarketSnapshot(
            "BTCUSDT",
            bid=Decimal("99.95"),
            ask=Decimal("100"),
            candles=[
                candle(1, "105", "105"),
                candle(2, "105", "104"),
                candle(3, "104", "103"),
                candle(4, "103", "102"),
                candle(5, "102", "101"),
                candle(6, "101", "100", "15"),
            ],
        )
    ]

    candidate = AutoSellScanner(("BTCUSDT",), Decimal("4"), Decimal("10")).select(snapshots)

    assert candidate is not None
    assert candidate.symbol == "BTCUSDT"
    assert candidate.reference_price == Decimal("99.95")
    assert candidate.score > Decimal("4")
    assert "negative 1h momentum" in candidate.reasons
    assert "bearish volume spike" in candidate.reasons


def test_auto_sell_scanner_rejects_sideways_holding():
    snapshots = [
        AutoSellMarketSnapshot(
            "BTCUSDT",
            bid=Decimal("99.95"),
            ask=Decimal("100"),
            candles=[
                candle(1, "100", "100"),
                candle(2, "100", "100.1"),
                candle(3, "100.1", "100"),
                candle(4, "100", "100.05"),
                candle(5, "100.05", "100"),
                candle(6, "100", "100.02", "8"),
            ],
        )
    ]

    assert AutoSellScanner(("BTCUSDT",), Decimal("4"), Decimal("10")).select(snapshots) is None


def test_auto_sell_scanner_uses_symbol_order_to_break_score_ties():
    btc_snapshot = AutoSellMarketSnapshot(
        "BTCUSDT",
        bid=Decimal("99.95"),
        ask=Decimal("100"),
        candles=[
            candle(1, "105", "105"),
            candle(2, "105", "104"),
            candle(3, "104", "103"),
            candle(4, "103", "102"),
            candle(5, "102", "101"),
            candle(6, "101", "100", "15"),
        ],
    )
    eth_snapshot = AutoSellMarketSnapshot(
        "ETHUSDT",
        bid=Decimal("99.95"),
        ask=Decimal("100"),
        candles=[
            candle(1, "105", "105"),
            candle(2, "105", "104"),
            candle(3, "104", "103"),
            candle(4, "103", "102"),
            candle(5, "102", "101"),
            candle(6, "101", "100", "15"),
        ],
    )

    candidate = AutoSellScanner(("ETHUSDT", "BTCUSDT"), Decimal("4"), Decimal("10")).select(
        [btc_snapshot, eth_snapshot]
    )

    assert candidate is not None
    assert candidate.symbol == "ETHUSDT"
