"""Tests for resolution analysis (python/horizon/resolution.py)."""

import time
from unittest.mock import patch

import pytest


# ---------------------------------------------------------------------------
# Config defaults
# ---------------------------------------------------------------------------


def test_resolution_config_defaults():
    from horizon.resolution import ResolutionConfig

    cfg = ResolutionConfig()
    assert cfg.provider == "anthropic"
    assert cfg.model == ""
    assert cfg.ambiguity_threshold == 0.6
    assert cfg.cache_ttl == 3600.0


def test_resolution_config_custom():
    from horizon.resolution import ResolutionConfig

    cfg = ResolutionConfig(provider="openai", ambiguity_threshold=0.8, cache_ttl=7200.0)
    assert cfg.provider == "openai"
    assert cfg.ambiguity_threshold == 0.8
    assert cfg.cache_ttl == 7200.0


# ---------------------------------------------------------------------------
# Data classes
# ---------------------------------------------------------------------------


def test_resolution_condition_frozen():
    from horizon.resolution import ResolutionCondition

    cond = ResolutionCondition(
        description="BTC must close above $100k",
        source="CoinGecko",
        verifiable=True,
        ambiguity_notes="Close time TBD",
    )
    assert cond.description == "BTC must close above $100k"
    assert cond.verifiable is True
    with pytest.raises(AttributeError):
        cond.description = "Changed"


def test_resolution_analysis_fields():
    from horizon.resolution import ResolutionAnalysis, ResolutionCondition

    analysis = ResolutionAnalysis(
        market_id="m1",
        market_title="Will BTC hit 100k?",
        resolution_source="CoinGecko",
        conditions=[
            ResolutionCondition("Price above $100k", "CoinGecko", True, ""),
        ],
        ambiguity_score=0.3,
        edge_cases=["Briefly touching 100k"],
        timing_risks=["Market close timing"],
        resolution_type="threshold",
        estimated_resolution_date="2026-12-31",
        risk_level="low",
        reasoning="Clear threshold condition",
        timestamp=1700000000.0,
    )
    assert analysis.market_id == "m1"
    assert analysis.ambiguity_score == 0.3
    assert analysis.risk_level == "low"
    assert analysis.resolution_type == "threshold"
    assert len(analysis.conditions) == 1
    assert len(analysis.edge_cases) == 1


# ---------------------------------------------------------------------------
# Prompt building
# ---------------------------------------------------------------------------


def test_build_resolution_prompt():
    from horizon.resolution import _build_resolution_prompt

    market_data = {
        "title": "Will X happen?",
        "description": "X resolves YES if...",
        "resolution_source": "AP News",
        "end_date": "2026-12-31",
    }
    prompt = _build_resolution_prompt(market_data)
    assert "Will X happen?" in prompt
    assert "AP News" in prompt
    assert "2026-12-31" in prompt
    assert "ambiguity_score" in prompt


# ---------------------------------------------------------------------------
# Response parsing
# ---------------------------------------------------------------------------


def test_parse_resolution_response_valid():
    from horizon.resolution import _parse_resolution_response

    text = '''{
        "resolution_source": "AP News",
        "conditions": [{"description": "Event occurs", "source": "AP", "verifiable": true, "ambiguity_notes": "Clear"}],
        "ambiguity_score": 0.2,
        "edge_cases": ["Edge case 1"],
        "timing_risks": ["Before deadline"],
        "resolution_type": "binary_event",
        "estimated_resolution_date": "2026-06-01",
        "risk_level": "low",
        "reasoning": "Very clear conditions"
    }'''
    analysis = _parse_resolution_response(text, "m1", "Test Market")
    assert analysis.market_id == "m1"
    assert analysis.resolution_source == "AP News"
    assert analysis.ambiguity_score == 0.2
    assert analysis.risk_level == "low"
    assert len(analysis.conditions) == 1
    assert analysis.conditions[0].verifiable is True


def test_parse_resolution_response_invalid():
    from horizon.resolution import _parse_resolution_response

    analysis = _parse_resolution_response("garbage", "m1", "Test")
    assert analysis.market_id == "m1"
    assert analysis.ambiguity_score == 0.5  # default
    assert analysis.risk_level == "medium"  # default


def test_parse_resolution_response_clamps_ambiguity():
    from horizon.resolution import _parse_resolution_response

    text = '{"ambiguity_score": 1.5, "risk_level": "high"}'
    analysis = _parse_resolution_response(text, "m1", "Test")
    assert analysis.ambiguity_score == 1.0


# ---------------------------------------------------------------------------
# Resolution guard pipeline
# ---------------------------------------------------------------------------


def test_resolution_guard_blocks_high_risk():
    from horizon.resolution import resolution_guard, ResolutionConfig, _analysis_cache, ResolutionAnalysis

    # Pre-populate cache with high ambiguity
    _analysis_cache["risky-market"] = (time.time(), ResolutionAnalysis(
        market_id="risky-market",
        market_title="Risky",
        resolution_source="unknown",
        conditions=[],
        ambiguity_score=0.9,
        edge_cases=[],
        timing_risks=[],
        resolution_type="committee",
        estimated_resolution_date="unknown",
        risk_level="high",
        reasoning="Very ambiguous",
        timestamp=time.time(),
    ))

    config = ResolutionConfig(cache_ttl=3600.0)
    guard = resolution_guard(config=config, block_above_ambiguity=0.6)

    # Mock context
    from unittest.mock import MagicMock
    ctx = MagicMock()
    ctx.market.id = "risky-market"
    ctx.market.name = "Risky Market"
    ctx.params = {}

    guard(ctx)

    assert ctx.params.get("resolution_blocked") is True
    assert ctx.params.get("resolution_risk") == "high"

    # Clean up
    del _analysis_cache["risky-market"]


def test_resolution_guard_passes_low_risk():
    from horizon.resolution import resolution_guard, ResolutionConfig, _analysis_cache, ResolutionAnalysis

    # Pre-populate cache with low ambiguity
    _analysis_cache["safe-market"] = (time.time(), ResolutionAnalysis(
        market_id="safe-market",
        market_title="Safe",
        resolution_source="AP",
        conditions=[],
        ambiguity_score=0.2,
        edge_cases=[],
        timing_risks=[],
        resolution_type="binary_event",
        estimated_resolution_date="2026-06-01",
        risk_level="low",
        reasoning="Clear conditions",
        timestamp=time.time(),
    ))

    config = ResolutionConfig(cache_ttl=3600.0)
    guard = resolution_guard(config=config, block_above_ambiguity=0.6)

    from unittest.mock import MagicMock
    ctx = MagicMock()
    ctx.market.id = "safe-market"
    ctx.market.name = "Safe Market"
    ctx.params = {}

    guard(ctx)

    assert ctx.params.get("resolution_blocked") is False
    assert ctx.params.get("resolution_risk") == "low"

    # Clean up
    del _analysis_cache["safe-market"]


def test_resolution_guard_returns_callable():
    from horizon.resolution import resolution_guard

    fn = resolution_guard()
    assert callable(fn)
    assert fn.__name__ == "resolution_guard"


# ---------------------------------------------------------------------------
# Caching
# ---------------------------------------------------------------------------


def test_analysis_caching():
    from horizon.resolution import _analysis_cache, ResolutionAnalysis

    analysis = ResolutionAnalysis(
        market_id="cache-test",
        market_title="Test",
        resolution_source="AP",
        conditions=[],
        ambiguity_score=0.3,
        edge_cases=[],
        timing_risks=[],
        resolution_type="binary_event",
        estimated_resolution_date="unknown",
        risk_level="low",
        reasoning="Test",
        timestamp=time.time(),
    )
    _analysis_cache["cache-test"] = (time.time(), analysis)

    ts, cached = _analysis_cache["cache-test"]
    assert cached.ambiguity_score == 0.3

    # Clean up
    del _analysis_cache["cache-test"]


# ---------------------------------------------------------------------------
# LLM delegation
# ---------------------------------------------------------------------------


def test_call_resolution_llm_delegates():
    """_call_resolution_llm delegates to _call_llm_raw from horizon.llm."""
    from horizon.resolution import _call_resolution_llm, ResolutionConfig

    config = ResolutionConfig(provider="openai", model="gpt-4o")

    with patch("horizon.llm._call_llm_raw", return_value="mocked response") as mock_raw:
        result = _call_resolution_llm("test prompt", config)

    assert result == "mocked response"
    mock_raw.assert_called_once_with("test prompt", "openai", "gpt-4o")


# ---------------------------------------------------------------------------
# Exports
# ---------------------------------------------------------------------------


def test_analyze_resolution_exchange_default():
    """analyze_resolution defaults to exchange='polymarket' (backward compat)."""
    from horizon.resolution import analyze_resolution, ResolutionConfig

    llm_response = (
        '{"resolution_source": "AP", "conditions": [],'
        ' "ambiguity_score": 0.3, "edge_cases": [], "timing_risks": [],'
        ' "resolution_type": "binary_event", "estimated_resolution_date": "unknown",'
        ' "risk_level": "low", "reasoning": "Clear"}'
    )

    with patch("horizon.resolution._fetch_market_description") as mock_fetch, \
         patch("horizon.resolution._call_resolution_llm", return_value=llm_response):
        mock_fetch.return_value = {
            "title": "Test", "description": "Desc",
            "resolution_source": "AP", "end_date": "",
        }
        analysis = analyze_resolution(
            "test-slug",
            config=ResolutionConfig(cache_ttl=0),
        )

    mock_fetch.assert_called_once_with("test-slug", exchange="polymarket")
    assert analysis.risk_level == "low"


# ---------------------------------------------------------------------------
# Exports
# ---------------------------------------------------------------------------


def test_exports():
    import horizon

    assert hasattr(horizon, "ResolutionAnalysis")
    assert hasattr(horizon, "ResolutionCondition")
    assert hasattr(horizon, "ResolutionConfig")
    assert hasattr(horizon, "analyze_resolution")
    assert hasattr(horizon, "batch_analyze")
    assert hasattr(horizon, "resolution_guard")
