"""
Tests for FASE 4 — crypto ticker detection must use word boundaries.

Regression: short tickers were detected with substring matching over
question_lower, so non-crypto markets triggered crypto flags:

  "Israeli parliament dissolved"  contains "sol" → is_sol / is_altcoin
  "Will Canada win Group B"       contains "ada" → is_altcoin
  "Will Seth Moulton be the nominee" contains "eth" → is_eth

Those flags armed the BTC-dominance signal (btc_dom_lo=+0.06 observed in
production on politics markets).  The fix routes short tickers (btc, eth,
sol, xrp, doge, ltc, bnb, ada, avax) through has_token(), which requires
non-alphanumeric boundaries; long unambiguous names (bitcoin, ethereum,
solana, cardano, …) remain substrings.

The is_* flags are internal to evaluate(), so the integration tests assert
on btc_dom_lo parsed from the structured audit log (same technique as
test_bayesian_macro_signals.py), with btc_dominance=60 so the signal fires
whenever an ETH/altcoin flag is set.
"""
import asyncio
import logging
import re

import pytest

from bot.data.external import ExternalSignals
from bot.data.polymarket import Market
from bot.strategy.bayesian import BayesianStrategy, has_token

BTC_DOM_RE = re.compile(r"btc_dom_lo=([+-]\d+\.\d+)")


def _make_market(question: str, category: str) -> Market:
    return Market(
        id="mkt-test-1",
        condition_id="cond-test-1",
        question=question,
        yes_token_id="yes-tok",
        no_token_id="no-tok",
        yes_price=0.50,
        no_price=0.50,
        volume_24h=50_000.0,
        end_date="2026-07-15T00:00:00Z",
        active=True,
        category=category,
    )


def _make_signals() -> ExternalSignals:
    # btc_dominance=60 (>55) arms the BTC-dominance signal for any market
    # flagged as ETH / altcoin / general-crypto.
    return ExternalSignals(
        btc_price=100_000.0,
        btc_change_24h=10.0,
        eth_price=4_000.0,
        eth_change_24h=8.0,
        btc_dominance=60.0,
        fear_greed_index=80,
        fear_greed_label="greed",
        total_market_cap_change=5.0,
        valid=True,
    )


def _evaluate_and_parse_btc_dom(question: str, category: str, caplog) -> float:
    """Run BayesianStrategy.evaluate and return btc_dom_lo from the audit log."""
    strategy = BayesianStrategy(news=None, manifold=None, db=None)
    market = _make_market(question, category)
    with caplog.at_level(logging.INFO, logger="bot.strategy.bayesian"):
        asyncio.run(
            strategy.evaluate(market, _make_signals(), occupied_families=set())
        )
    for record in caplog.records:
        m = BTC_DOM_RE.search(record.getMessage())
        if m:
            return float(m.group(1))
    pytest.fail(
        "No SKIP_EDGE_NET/TRADE log line with btc_dom_lo found; "
        f"got: {[r.getMessage() for r in caplog.records]}"
    )


# ── has_token unit tests ─────────────────────────────────────────────────────

def test_has_token_rejects_substrings_inside_words():
    assert has_token("israeli parliament dissolved by june 30?", "sol") is False
    assert has_token("will canada win group b?", "ada") is False
    assert has_token("will seth moulton be the nominee?", "eth") is False

def test_has_token_matches_common_market_formats():
    assert has_token("will eth hit $5000?", "eth") is True
    assert has_token("$eth above $5000?", "eth") is True
    assert has_token("eth/usd above 5000?", "eth") is True
    assert has_token("will sol reach $200?", "sol") is True
    assert has_token("will ada reach $1?", "ada") is True
    assert has_token("BTC to $150k?", "btc") is True  # case-insensitive


# ── Regression: false positives must not arm the BTC-dominance signal ───────

def test_israeli_parliament_market_is_not_sol(caplog):
    """'dissolved' contains 'sol' — must NOT flag is_sol/is_altcoin."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Israeli parliament dissolved by June 30?", "politics", caplog
    )
    assert btc_dom_lo == 0.0

def test_canada_market_is_not_ada(caplog):
    """'Canada' contains 'ada' — must NOT flag is_altcoin."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Will Canada win Group B?", "events", caplog
    )
    assert btc_dom_lo == 0.0

def test_seth_moulton_market_is_not_eth(caplog):
    """'Seth' contains 'eth' — must NOT flag is_eth."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Will Seth Moulton be the nominee?", "politics", caplog
    )
    assert btc_dom_lo == 0.0


# ── Real ticker mentions must keep working ───────────────────────────────────

def test_eth_market_detected(caplog):
    """Standalone 'ETH' still flags is_eth: BTC-dom fires and momentum uses ETH."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Will ETH hit $5000?", "crypto/finance", caplog
    )
    assert btc_dom_lo != 0.0
    # Momentum picks the ETH branch only when is_eth is True.
    full_log = "\n".join(r.getMessage() for r in caplog.records)
    assert "ETH 24h: +8.0%" in full_log

def test_dollar_eth_market_detected(caplog):
    """'$ETH' format still flags is_eth."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "$ETH above $5000?", "crypto/finance", caplog
    )
    assert btc_dom_lo != 0.0
    full_log = "\n".join(r.getMessage() for r in caplog.records)
    assert "ETH 24h: +8.0%" in full_log

def test_sol_market_detected(caplog):
    """'SOL reach $200' still flags is_sol → is_altcoin → BTC-dom signal."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Will SOL reach $200?", "crypto/finance", caplog
    )
    # 'reach' → is_price_above, dominance 60 → -0.03 contribution → -0.06 log-odds
    assert btc_dom_lo == pytest.approx(-0.06, abs=1e-4)

def test_ada_market_detected(caplog):
    """'ADA reach $1' still flags is_altcoin."""
    btc_dom_lo = _evaluate_and_parse_btc_dom(
        "Will ADA reach $1?", "crypto/finance", caplog
    )
    assert btc_dom_lo == pytest.approx(-0.06, abs=1e-4)
