"""
用户测试：模拟原始会话中的两个异常场景，验证修复效果

场景 1：API 返回空错误消息 → 错误信息包含异常类型名（不再空）
场景 2：网络瞬断错误 → 自动重试 3 次后仍失败则终止
"""
import sys
from pathlib import Path
from unittest.mock import MagicMock, AsyncMock

import pytest

sys.path.insert(0, str(Path(__file__).parent.parent))


@pytest.mark.asyncio
async def test_scenario_1_empty_error_has_type_name():
    """场景 1：模型 API 返回空错误消息 → 错误信息包含异常类型名"""
    from aacode.core.main_agent import MainAgent
    import httpx

    agent = MainAgent.__new__(MainAgent)
    agent.skills_manager = MagicMock()
    agent.skills_manager.list_enabled_skills = MagicMock(return_value=[])
    agent.session_manager = MagicMock()
    agent.context_manager = MagicMock()

    mock_req = MagicMock()
    try:
        exc = httpx.RemoteProtocolError("", request=mock_req)
    except TypeError:
        exc = httpx.RemoteProtocolError("")

    agent._call_openai_api = AsyncMock(side_effect=exc)
    model_caller = agent._create_model_caller({"api_key": "sk-test"})

    with pytest.raises(RuntimeError) as exc_info:
        await model_caller([{"role": "user", "content": "hi"}])

    msg = str(exc_info.value)
    assert "RemoteProtocolError" in msg, f"Error message should contain type name, got: {msg}"


@pytest.mark.asyncio
async def test_scenario_2_retry_then_succeed():
    """场景 2：网络瞬断 → 自动重试后成功"""
    from aacode.core.main_agent import MainAgent
    import httpx

    agent = MainAgent.__new__(MainAgent)
    agent.skills_manager = MagicMock()
    agent.skills_manager.list_enabled_skills = MagicMock(return_value=[])
    agent.session_manager = MagicMock()
    agent.context_manager = MagicMock()

    mock_req = MagicMock()
    call_count = 0

    async def flaky_api(*args, **kwargs):
        nonlocal call_count
        call_count += 1
        if call_count < 2:
            raise httpx.RemoteProtocolError("Connection reset by peer", request=mock_req)
        return {"text": "OK, recovered!"}

    agent._call_openai_api = flaky_api
    model_caller = agent._create_model_caller({"api_key": "sk-test"})

    result = await model_caller([{"role": "user", "content": "hi"}])

    assert call_count == 2, f"Expected 2 calls, got {call_count}"
    assert result["text"] == "OK, recovered!", f"Expected 'OK, recovered!', got: {result}"


@pytest.mark.asyncio
async def test_scenario_3_retry_exhausted():
    """场景 3：持续故障 → 重试 3 次后报错（带类型名）"""
    from aacode.core.main_agent import MainAgent
    import httpx

    agent = MainAgent.__new__(MainAgent)
    agent.skills_manager = MagicMock()
    agent.skills_manager.list_enabled_skills = MagicMock(return_value=[])
    agent.session_manager = MagicMock()
    agent.context_manager = MagicMock()

    mock_req = MagicMock()
    agent._call_openai_api = AsyncMock(
        side_effect=httpx.RemoteProtocolError("Server disconnected", request=mock_req)
    )
    model_caller = agent._create_model_caller({"api_key": "sk-test"})

    with pytest.raises(RuntimeError) as exc_info:
        await model_caller([{"role": "user", "content": "hi"}])

    msg = str(exc_info.value)
    calls = agent._call_openai_api.call_count
    assert calls == 3, f"Expected 3 retry calls, got {calls}"
    assert "RemoteProtocolError" in msg, f"Error message should contain type name, got: {msg}"


@pytest.mark.asyncio
async def test_scenario_4_auth_error_no_retry():
    """场景 4：认证错误 → 不重试，直接终止"""
    from aacode.core.main_agent import MainAgent
    import openai

    agent = MainAgent.__new__(MainAgent)
    agent.skills_manager = MagicMock()
    agent.skills_manager.list_enabled_skills = MagicMock(return_value=[])
    agent.session_manager = MagicMock()
    agent.context_manager = MagicMock()

    mock_resp = MagicMock()
    mock_resp.status_code = 401
    mock_resp.request = MagicMock()

    agent._call_openai_api = AsyncMock(
        side_effect=openai.AuthenticationError("Invalid API key", response=mock_resp, body={})
    )
    model_caller = agent._create_model_caller({"api_key": "sk-test"})

    with pytest.raises(RuntimeError) as exc_info:
        await model_caller([{"role": "user", "content": "hi"}])

    msg = str(exc_info.value)
    calls = agent._call_openai_api.call_count
    assert calls == 1, f"Auth errors should not retry, got {calls} calls"
    assert "AuthenticationError" in msg, f"Error message should contain type name, got: {msg}"
