"""Test that the Anthropic OAuth identity block is always included in API requests."""

import pytest
from unittest.mock import AsyncMock, patch, MagicMock

import httpx

from nanobot.providers.anthropic_oauth import AnthropicOAuthProvider
from nanobot.providers.oauth_utils import get_claude_code_system_prefix


IDENTITY_TEXT = get_claude_code_system_prefix()


@pytest.fixture
def provider():
    return AnthropicOAuthProvider(
        oauth_token="sk-ant-oat01-test-token",
        default_model="claude-opus-4-5",
    )


def _mock_response(status_code=200, json_data=None):
    """Create a mock httpx.Response."""
    resp = MagicMock(spec=httpx.Response)
    resp.status_code = status_code
    resp.headers = {}
    resp.text = ""
    resp.json.return_value = json_data or {
        "content": [{"type": "text", "text": "ok"}],
        "stop_reason": "end_turn",
        "usage": {"input_tokens": 1, "output_tokens": 1},
    }
    return resp


@pytest.mark.asyncio
async def test_identity_block_present_with_system_prompt(provider):
    """When a system prompt is provided, identity block is the first system block."""
    mock_client = AsyncMock()
    mock_client.post.return_value = _mock_response()
    provider._client = mock_client

    await provider._make_request(
        messages=[{"role": "user", "content": "hello"}],
        system="You are a helpful assistant.",
    )

    call_kwargs = mock_client.post.call_args
    payload = call_kwargs.kwargs["json"] if "json" in call_kwargs.kwargs else call_kwargs[1]["json"]
    system_blocks = payload["system"]

    assert len(system_blocks) == 2
    assert system_blocks[0]["type"] == "text"
    assert system_blocks[0]["text"] == IDENTITY_TEXT
    assert system_blocks[1]["text"] == "You are a helpful assistant."


@pytest.mark.asyncio
async def test_identity_block_present_without_system_prompt(provider):
    """When no system prompt is provided, identity block is still included.

    This is the critical fix: extract_facts and similar calls pass system=None,
    but Anthropic requires the identity block for OAuth tokens.
    """
    mock_client = AsyncMock()
    mock_client.post.return_value = _mock_response()
    provider._client = mock_client

    await provider._make_request(
        messages=[{"role": "user", "content": "extract facts"}],
        system=None,
    )

    call_kwargs = mock_client.post.call_args
    payload = call_kwargs.kwargs["json"] if "json" in call_kwargs.kwargs else call_kwargs[1]["json"]
    system_blocks = payload["system"]

    assert len(system_blocks) == 1
    assert system_blocks[0]["type"] == "text"
    assert system_blocks[0]["text"] == IDENTITY_TEXT


@pytest.mark.asyncio
async def test_identity_block_present_with_empty_string_system(provider):
    """Empty string system prompt should still include the identity block."""
    mock_client = AsyncMock()
    mock_client.post.return_value = _mock_response()
    provider._client = mock_client

    await provider._make_request(
        messages=[{"role": "user", "content": "hello"}],
        system="",
    )

    call_kwargs = mock_client.post.call_args
    payload = call_kwargs.kwargs["json"] if "json" in call_kwargs.kwargs else call_kwargs[1]["json"]
    system_blocks = payload["system"]

    # Empty string is falsy, so should go through the else branch
    assert len(system_blocks) == 1
    assert system_blocks[0]["text"] == IDENTITY_TEXT
