"""
Tests for FASE 3 — macro signals (momentum, Fear & Greed) must not apply to
non-price markets (politics / tech / events).

Regression: for "Will X win the election?"-style questions, is_price_above is
False, so positive BTC momentum and high Fear & Greed were sign-flipped into
evidence AGAINST the YES outcome. The fix skips both signals entirely for
politics/tech/events, leaving their contributions (and feat_mom_lo /
feat_fg_lo) at 0.0.

evaluate_market only returns a TradingSignal on the TRADE path; on skips it
returns None but always emits a structured log line containing the per-feature
log-odds (fg_lo=… mom_lo=…). The tests parse that line via caplog.
"""
import asyncio
import logging
import math
import re

import pytest

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

FEAT_RE = re.compile(r"fg_lo=([+-]\d+\.\d+) mom_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:
    # Strong bullish macro environment: BTC +10%, extreme greed.
    return ExternalSignals(
        btc_price=100_000.0,
        btc_change_24h=10.0,
        eth_price=4_000.0,
        eth_change_24h=8.0,
        btc_dominance=50.0,
        fear_greed_index=80,
        fear_greed_label="greed",
        total_market_cap_change=5.0,
        valid=True,
    )


def _evaluate_and_parse_feats(question: str, category: str, caplog) -> tuple[float, float]:
    """Run BayesianStrategy.evaluate and return (feat_fg_lo, feat_mom_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 = FEAT_RE.search(record.getMessage())
        if m:
            return float(m.group(1)), float(m.group(2))
    pytest.fail(
        "No SKIP_EDGE_NET/TRADE log line with feature contributions found; "
        f"got: {[r.getMessage() for r in caplog.records]}"
    )


def test_politics_market_ignores_momentum_and_fear_greed(caplog):
    """Political market with BTC +10% and F&G=80 → both contributions 0.0."""
    feat_fg_lo, feat_mom_lo = _evaluate_and_parse_feats(
        "Will John Smith win the election?", "politics", caplog
    )
    assert feat_mom_lo == 0.0
    assert feat_fg_lo == 0.0
    # The signal sources must not mention momentum or Fear & Greed either.
    full_log = "\n".join(r.getMessage() for r in caplog.records)
    assert "Fear&Greed" not in full_log
    assert "24h" not in full_log


def test_tech_and_events_markets_ignore_macro_signals(caplog):
    for category in ("tech", "events"):
        caplog.clear()
        feat_fg_lo, feat_mom_lo = _evaluate_and_parse_feats(
            "Will the product launch happen this quarter?", category, caplog
        )
        assert feat_mom_lo == 0.0, f"momentum applied to {category} market"
        assert feat_fg_lo == 0.0, f"Fear&Greed applied to {category} market"


def test_btc_market_keeps_momentum_and_fear_greed(caplog):
    """BTC price market with BTC +10% and F&G=80 → current behavior preserved."""
    feat_fg_lo, feat_mom_lo = _evaluate_and_parse_feats(
        "Will Bitcoin be above $150,000 on July 1?", "crypto/finance", caplog
    )
    assert feat_mom_lo > 0
    assert feat_fg_lo > 0
    # Exact values: is_price_above=True ("above"), so contributions are positive.
    # momentum: tanh(10/20) * 0.15, ×2 → log-odds.  F&G>70: +0.06, ×2 → log-odds.
    assert feat_mom_lo == pytest.approx(math.tanh(10 / 20) * 0.15 * 2, abs=1e-4)
    assert feat_fg_lo == pytest.approx(0.06 * 2, abs=1e-4)
    full_log = "\n".join(r.getMessage() for r in caplog.records)
    assert "Fear&Greed: 80 (greed)" in full_log
    assert "BTC 24h: +10.0%" in full_log


def test_btc_below_market_sign_flip_preserved(caplog):
    """'below' market: bullish macro lowers YES probability (sign flip intact)."""
    feat_fg_lo, feat_mom_lo = _evaluate_and_parse_feats(
        "Will Bitcoin drop below $50,000 by August?", "crypto/finance", caplog
    )
    assert feat_mom_lo < 0
    assert feat_fg_lo < 0
