"""BL-06: Agent auth must use per-server agent_api_key only (no global API_KEY fallback)."""

from unittest.mock import AsyncMock, MagicMock

import pytest

from server.api.agent import _verify_server_api_key
from server.application.services.script_service import ScriptService
from server.config import settings


def _fake_server(*, agent_api_key=None, name="test-srv"):
    srv = MagicMock()
    srv.name = name
    srv.agent_api_key = agent_api_key
    return srv


@pytest.fixture
def mock_service():
    return AsyncMock()


@pytest.mark.asyncio
async def test_verify_server_key_matches_per_server(mock_service):
    mock_service.get_server.return_value = _fake_server(agent_api_key="nxs-abc")
    result = await _verify_server_api_key(1, "nxs-abc", mock_service)
    assert result is not None
    assert result.agent_api_key == "nxs-abc"
    mock_service.get_server.assert_called_once_with(1)


@pytest.mark.asyncio
async def test_verify_server_key_single_get_server_per_auth_check(mock_service):
    """Regression: auth path must not double-query the same server_id (BL-06 patrol)."""
    mock_service.get_server.return_value = _fake_server(agent_api_key="nxs-once")
    await _verify_server_api_key(7, "nxs-once", mock_service)
    mock_service.get_server.assert_called_once_with(7)


@pytest.mark.asyncio
async def test_verify_server_key_rejects_wrong_key(mock_service):
    mock_service.get_server.return_value = _fake_server(agent_api_key="nxs-abc")
    assert await _verify_server_api_key(1, "nxs-wrong", mock_service) is None


@pytest.mark.asyncio
async def test_verify_server_key_rejects_global_api_key(mock_service, monkeypatch):
    monkeypatch.setattr(settings, "API_KEY", "global-secret-key")
    mock_service.get_server.return_value = _fake_server(agent_api_key="nxs-abc")
    assert await _verify_server_api_key(1, "global-secret-key", mock_service) is None


@pytest.mark.asyncio
async def test_verify_server_key_no_per_server_key_rejects_global(mock_service, monkeypatch):
    monkeypatch.setattr(settings, "API_KEY", "global-secret-key")
    mock_service.get_server.return_value = _fake_server(agent_api_key=None)
    assert await _verify_server_api_key(1, "global-secret-key", mock_service) is None


@pytest.mark.asyncio
async def test_verify_server_key_server_not_found(mock_service):
    mock_service.get_server.return_value = None
    assert await _verify_server_api_key(99, "any-key", mock_service) is None


@pytest.mark.asyncio
async def test_verify_server_key_db_error_fail_closed(mock_service):
    mock_service.get_server.side_effect = RuntimeError("db down")
    assert await _verify_server_api_key(1, "any-key", mock_service) is None


@pytest.mark.asyncio
async def test_script_service_agent_key_requires_per_server():
    repo = AsyncMock()
    repo.get_by_id.return_value = _fake_server(agent_api_key=None)
    svc = ScriptService(
        script_repo=AsyncMock(),
        execution_repo=AsyncMock(),
        credential_repo=AsyncMock(),
        server_repo=repo,
        audit_repo=AsyncMock(),
    )
    with pytest.raises(ValueError, match="未设置 Agent API Key"):
        await svc._agent_api_key_for_server(42)


@pytest.mark.asyncio
async def test_script_service_agent_key_returns_per_server():
    repo = AsyncMock()
    repo.get_by_id.return_value = _fake_server(agent_api_key="nxs-callback")
    svc = ScriptService(
        script_repo=AsyncMock(),
        execution_repo=AsyncMock(),
        credential_repo=AsyncMock(),
        server_repo=repo,
        audit_repo=AsyncMock(),
    )
    assert await svc._agent_api_key_for_server(1) == "nxs-callback"
