"""
tests/test_caller_registry.py
─────────────────────────────────────────────────────────────────
Operation Ollama-First v5.0 / Phase 16 — caller_registry 集中管理驗證

驗證面：
  T1. CALLER_REGISTRY 含 ADR-028 列舉的 30+ caller
  T2. is_known_caller 對白名單回 True / 未知回 False
  T3. assert_known_caller(strict=False) → log warning 不 raise
  T4. assert_known_caller(strict=True) → 未知 raise ValueError
  T5. list_callers_by_service 分組正確
  T6. ai_call_logger 整合：未知 caller 不阻擋（log warning）
"""

import logging

import pytest


def test_registry_contains_core_callers():
    """ADR-028 白名單核心 caller 必在 registry"""
    from services.llm_caller_registry import CALLER_REGISTRY

    must_have = {
        # Hermes
        'hermes_analyst', 'hermes_intent',
        # OpenClaw
        'openclaw_daily', 'openclaw_weekly', 'openclaw_monthly',
        'openclaw_meta', 'openclaw_qa',
        'openclaw_qa_gemini_fallback', 'openclaw_qa_nim',
        'openclaw_daily_gemini_fallback', 'openclaw_weekly_gemini_fallback',
        'openclaw_monthly_gemini_fallback', 'openclaw_meta_gemini_fallback',
        'openclaw_daily_insight_gemini_fallback',
        'openclaw_daily_nim', 'openclaw_weekly_nim',
        'openclaw_monthly_nim', 'openclaw_meta_nim',
        'openclaw_daily_insight_nim',
        # MCP
        'mcp_l1_grounding', 'mcp_collector',
        # Code Review
        'code_review_hermes', 'code_review_openclaw', 'code_review_elephant',
        # NemoTron / EA
        'nemotron_dispatch', 'ea_engine',
        # PPT
        'ppt_gemini', 'ppt_ollama', 'ppt_nim', 'ppt_vision',
        # KM Embedding
        'km_embedding_worker', 'km_embedding_realtime',
        # Sales / Trend
        'sales_copy', 'trend_match', 'trend_qa', 'product_insights',
        # Bot
        'openclaw_bot_main', 'openclaw_bot_gemini', 'openclaw_bot_nim',
        'openclaw_bot_image', 'openclaw_bot_image_gemini',
    }

    missing = must_have - CALLER_REGISTRY
    assert not missing, f"registry 缺 {len(missing)} 個關鍵 caller: {missing}"


def test_is_known_caller():
    from services.llm_caller_registry import is_known_caller

    assert is_known_caller('hermes_analyst') is True
    assert is_known_caller('openclaw_qa') is True
    assert is_known_caller('openclaw_qa_gemini_fallback') is True
    assert is_known_caller('openclaw_qa_nim') is True
    assert is_known_caller('not_a_real_caller') is False
    assert is_known_caller('') is False
    assert is_known_caller('GeMiNi_Caller_Wrong_Case') is False


def test_assert_known_caller_strict_false_only_warns(caplog):
    """strict=False（預設）→ 不在 registry 只 log warning"""
    from services.llm_caller_registry import assert_known_caller

    with caplog.at_level(logging.WARNING):
        assert_known_caller('totally_made_up_caller', strict=False)
    # 應有 warning
    warnings = [r for r in caplog.records if r.levelno >= logging.WARNING]
    assert len(warnings) >= 1
    assert 'unknown caller' in warnings[0].message.lower() or \
           'totally_made_up_caller' in warnings[0].message


def test_assert_known_caller_strict_true_raises():
    from services.llm_caller_registry import assert_known_caller

    with pytest.raises(ValueError, match='unknown caller'):
        assert_known_caller('definitely_not_real', strict=True)


def test_assert_known_caller_passes_for_real_caller():
    """合法 caller → 不 raise / 不 warn"""
    from services.llm_caller_registry import assert_known_caller
    # 不該 raise
    assert_known_caller('hermes_analyst', strict=True)
    assert_known_caller('openclaw_qa', strict=False)


def test_list_callers_by_service_structure():
    from services.llm_caller_registry import list_callers_by_service, CALLER_REGISTRY

    grouped = list_callers_by_service()
    expected_groups = {'hermes', 'openclaw', 'openclaw_bot', 'mcp', 'code_review',
                       'ppt', 'tg_bot', 'km_embedding', 'sales_trend', 'misc'}
    assert expected_groups.issubset(grouped.keys())

    # 每組至少 1 個
    for group, callers in grouped.items():
        assert isinstance(callers, list)
        assert len(callers) >= 1, f"group '{group}' 是空的"

    # hermes 至少含 hermes_analyst
    assert 'hermes_analyst' in grouped['hermes']


def test_ai_call_logger_integration_does_not_block_unknown_caller(caplog):
    """ai_call_logger 收到 unknown caller 應 log warning 但不阻擋 context manager"""
    import os
    os.environ['AI_CALL_LOGGING_ENABLED'] = 'false'  # 跳過 DB 寫入
    try:
        from services.ai_call_logger import log_ai_call

        with caplog.at_level(logging.WARNING):
            with log_ai_call(
                caller='unknown_test_caller_xyz',  # 故意不在 registry
                provider='gcp_ollama',
                model='hermes3:latest',
            ) as ctx:
                ctx.set_tokens(input=100, output=50)
        # context manager 不 raise，正常結束
        # 應該有 warning（caller 不在 registry）
        warnings = [r for r in caplog.records if r.levelno >= logging.WARNING]
        assert any('unknown_test_caller' in r.message.lower() or
                   'unknown caller' in r.message.lower()
                   for r in warnings), \
            f"應 warn unknown caller，實際 warnings: {[r.message for r in warnings]}"
    finally:
        os.environ.pop('AI_CALL_LOGGING_ENABLED', None)


def test_registry_is_immutable_frozenset():
    """CALLER_REGISTRY 是 frozenset 不可變動"""
    from services.llm_caller_registry import CALLER_REGISTRY

    assert isinstance(CALLER_REGISTRY, frozenset)
    with pytest.raises(AttributeError):
        CALLER_REGISTRY.add('attempted_mutation')  # type: ignore
