"""LLM provider clients, the factory, and the scripted fake."""

from __future__ import annotations

import httpx
import pytest
from legate.config import Settings
from legate.llm.base import LLMError, LLMMessage
from legate.llm.factory import build_llm_client
from legate.llm.fake import FakeLLMClient
from legate.llm.ollama import OllamaClient
from legate.llm.openrouter import OpenRouterClient

MESSAGES = [LLMMessage("system", "be helpful"), LLMMessage("user", "hi")]


async def test_fake_client_returns_scripted_then_raises():
    fake = FakeLLMClient(["one"])
    resp = await fake.complete(MESSAGES, model="fake")
    assert resp.content == "one"
    assert resp.total_tokens > 0
    assert fake.calls and fake.calls[0][0].content == "be helpful"
    with pytest.raises(LLMError):
        await fake.complete(MESSAGES, model="fake")


async def test_openrouter_parses_completion_and_usage():
    def handler(request: httpx.Request) -> httpx.Response:
        assert request.headers["authorization"] == "Bearer sk-test"
        return httpx.Response(
            200,
            json={
                "model": "openai/gpt-4o",
                "choices": [{"message": {"content": "hello there"}}],
                "usage": {"prompt_tokens": 11, "completion_tokens": 5},
            },
        )

    async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as http:
        client = OpenRouterClient(api_key="sk-test", http_client=http)
        resp = await client.complete(MESSAGES, model="openai/gpt-4o")

    assert resp.content == "hello there"
    assert resp.prompt_tokens == 11
    assert resp.completion_tokens == 5


async def test_openrouter_raises_on_bad_shape():
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(200, json={"unexpected": True})

    async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as http:
        client = OpenRouterClient(api_key="sk-test", http_client=http)
        with pytest.raises(LLMError):
            await client.complete(MESSAGES, model="x")


async def test_ollama_parses_message_and_token_counts():
    def handler(request: httpx.Request) -> httpx.Response:
        return httpx.Response(
            200,
            json={
                "model": "llama3",
                "message": {"content": "local reply"},
                "prompt_eval_count": 7,
                "eval_count": 4,
            },
        )

    async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as http:
        client = OllamaClient(http_client=http)
        resp = await client.complete(MESSAGES, model="llama3")

    assert resp.content == "local reply"
    assert resp.prompt_tokens == 7
    assert resp.completion_tokens == 4


def test_factory_builds_supported_providers():
    assert isinstance(build_llm_client("ollama", Settings()), OllamaClient)
    with_key = Settings(llm_api_key="sk-live")
    assert isinstance(build_llm_client("openrouter", with_key), OpenRouterClient)


def test_factory_rejects_missing_key_and_unknown_provider():
    with pytest.raises(LLMError):
        build_llm_client("openrouter", Settings(llm_api_key=""))
    with pytest.raises(LLMError):
        build_llm_client("anthropic", Settings())
