"""Tests for BrainstormRouter Python SDK."""

from __future__ import annotations

import json
from unittest.mock import MagicMock, patch

import pytest

from brainstormrouter import (
    AsyncBrainstormRouter,
    BrainstormRouter,
    BrainstormRouterError,
    GuardianInfo,
    parse_guardian_stream_done,
)
from brainstormrouter._resource import Resource


# ── Client instantiation ──────────────────────────────────────────────


def test_default_base_url():
    client = BrainstormRouter(api_key="test-key")
    assert client._br_base_url == "https://api.brainstormrouter.com"


def test_custom_base_url():
    client = BrainstormRouter(api_key="test-key", base_url="http://localhost:18790")
    assert client._br_base_url == "http://localhost:18790"


def test_env_api_key():
    with patch.dict("os.environ", {"BRAINSTORMROUTER_API_KEY": "br_live_env"}):
        client = BrainstormRouter()
        assert client._br_api_key == "br_live_env"


def test_explicit_key_overrides_env():
    with patch.dict("os.environ", {"BRAINSTORMROUTER_API_KEY": "br_live_env"}):
        client = BrainstormRouter(api_key="br_live_explicit")
        assert client._br_api_key == "br_live_explicit"


# ── Resource namespaces exist ─────────────────────────────────────────


def test_sync_has_all_resources():
    client = BrainstormRouter(api_key="test")
    assert hasattr(client, "providers")
    assert hasattr(client, "presets")
    assert hasattr(client, "prompts")
    assert hasattr(client, "memory")
    assert hasattr(client, "guardrails")
    assert hasattr(client, "observability")
    assert hasattr(client, "governance")
    assert hasattr(client, "mcp")
    assert hasattr(client, "br_models")


def test_async_has_all_resources():
    client = AsyncBrainstormRouter(api_key="test")
    assert hasattr(client, "providers")
    assert hasattr(client, "presets")
    assert hasattr(client, "prompts")
    assert hasattr(client, "memory")
    assert hasattr(client, "guardrails")
    assert hasattr(client, "observability")
    assert hasattr(client, "governance")
    assert hasattr(client, "mcp")
    assert hasattr(client, "br_models")


# ── Resource base class ───────────────────────────────────────────────


def test_resource_error_handling():
    """Test that API errors are properly wrapped."""
    resource = Resource("http://localhost", lambda: {})

    mock_response = MagicMock()
    mock_response.status_code = 403
    mock_response.json.return_value = {
        "error": {"message": "Invalid API key", "type": "authentication_error"}
    }

    with patch("httpx.Client") as mock_client:
        mock_client.return_value.__enter__ = MagicMock(return_value=mock_client.return_value)
        mock_client.return_value.__exit__ = MagicMock(return_value=False)
        mock_client.return_value.request.return_value = mock_response

        with pytest.raises(BrainstormRouterError) as exc_info:
            resource._get("/v1/test")

        assert exc_info.value.status == 403
        assert exc_info.value.error_type == "authentication_error"
        assert "Invalid API key" in str(exc_info.value)


def test_resource_successful_request():
    """Test successful API request."""
    resource = Resource("http://localhost", lambda: {"Authorization": "Bearer test"})

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"providers": [], "total": 0}

    with patch("httpx.Client") as mock_client:
        mock_client.return_value.__enter__ = MagicMock(return_value=mock_client.return_value)
        mock_client.return_value.__exit__ = MagicMock(return_value=False)
        mock_client.return_value.request.return_value = mock_response

        result = resource._get("/v1/providers")
        assert result == {"providers": [], "total": 0}


# ── Guardian parsing ──────────────────────────────────────────────────


def test_guardian_stream_done_with_data():
    data = '[DONE] {"guardian":{"efficiency":1.5,"actualCost":0.04,"savings":0.02}}'
    result = parse_guardian_stream_done(data)
    assert result is not None
    assert result.efficiency == 1.5
    assert result.actual_cost == 0.04
    assert result.savings == 0.02


def test_guardian_stream_done_empty():
    result = parse_guardian_stream_done("[DONE]")
    assert result is None


def test_guardian_stream_done_not_done():
    result = parse_guardian_stream_done("data: {}")
    assert result is None


def test_guardian_stream_done_invalid_json():
    result = parse_guardian_stream_done("[DONE] not-json")
    assert result is None


# ── Provider resource methods ─────────────────────────────────────────


def test_providers_register_builds_correct_body():
    """Verify register sends the correct payload."""
    resource = Resource("http://localhost", lambda: {})

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"id": "1", "provider": "groq", "masked_key": "gsk_..."}

    with patch("httpx.Client") as mock_client:
        mock_client.return_value.__enter__ = MagicMock(return_value=mock_client.return_value)
        mock_client.return_value.__exit__ = MagicMock(return_value=False)
        mock_client.return_value.request.return_value = mock_response

        from brainstormrouter.resources.providers import Providers
        providers = Providers("http://localhost", lambda: {})
        result = providers.register("groq", api_key="gsk_test123")

        call_args = mock_client.return_value.request.call_args
        assert call_args[1]["json"] == {"provider": "groq", "api_key": "gsk_test123"}


# ── Memory resource methods ───────────────────────────────────────────


def test_memory_append_with_block():
    """Verify append sends block param."""
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"entry": {"id": "1", "fact": "test", "block": "human"}}

    with patch("httpx.Client") as mock_client:
        mock_client.return_value.__enter__ = MagicMock(return_value=mock_client.return_value)
        mock_client.return_value.__exit__ = MagicMock(return_value=False)
        mock_client.return_value.request.return_value = mock_response

        from brainstormrouter.resources.memory import Memory
        memory = Memory("http://localhost", lambda: {})
        memory.append("User prefers dark mode", block="human", pinned=True)

        call_args = mock_client.return_value.request.call_args
        assert call_args[1]["json"] == {
            "fact": "User prefers dark mode",
            "block": "human",
            "pinned": True,
        }


# ── Models/leaderboard ────────────────────────────────────────────────


def test_leaderboard_query_params():
    """Verify leaderboard passes query params correctly."""
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"object": "list", "data": [], "model_count": 0}

    with patch("httpx.Client") as mock_client:
        mock_client.return_value.__enter__ = MagicMock(return_value=mock_client.return_value)
        mock_client.return_value.__exit__ = MagicMock(return_value=False)
        mock_client.return_value.request.return_value = mock_response

        from brainstormrouter.resources.models import Models
        models = Models("http://localhost", lambda: {})
        models.leaderboard(sort="quality", provider="openai", limit=10)

        call_args = mock_client.return_value.request.call_args
        assert call_args[1]["params"] == {"sort": "quality", "provider": "openai", "limit": "10"}
