"""
Tests for ModelsClient.

Uses mock to simulate server responses.
"""

import pytest
from unittest.mock import patch

from boring_os import BoringOS
from boring_os.model_models import ModelCompletion, ModelEmbedding, ModelInfo


# Sample data
SAMPLE_MODEL_COMPLETION = {
    "text": "Gravity is a force that pulls objects together.",
    "model": "claude-sonnet-4",
    "provider": "anthropic",
    "usage": {"input_tokens": 25, "output_tokens": 50, "cost": 0.001},
    "finish_reason": "stop",
    "tool_calls": [],
}

SAMPLE_MODEL_EMBEDDING = {
    "embeddings": [[0.1, 0.2, 0.3], [-0.1, -0.2, -0.3]],
    "model": "text-embedding-3-small",
    "usage": {"total_tokens": 10},
}

SAMPLE_MODELS_LIST = {
    "models": [
        {
            "name": "claude-sonnet-4",
            "provider": "anthropic",
            "input_price_per_million": 3.0,
            "output_price_per_million": 15.0,
            "max_context_tokens": 200000,
        },
    ],
}


class TestModelsClientComplete:
    """Tests for models.complete()."""

    def test_complete_returns_completion(self, client):
        """complete() returns a parsed ModelCompletion."""
        with patch.object(client, "_request", return_value=SAMPLE_MODEL_COMPLETION):
            result = client.models.complete(
                model="claude-sonnet-4",
                messages=[{"role": "user", "content": "Hello"}],
            )

        assert isinstance(result, ModelCompletion)
        assert result.text == "Gravity is a force that pulls objects together."
        assert result.model == "claude-sonnet-4"
        assert result.cost == 0.001

    def test_complete_sends_optional_params(self, client):
        """complete() includes temperature and max_tokens when set."""
        with patch.object(client, "_request", return_value=SAMPLE_MODEL_COMPLETION) as mock:
            client.models.complete(
                model="gpt-4.1-mini",
                messages=[{"role": "user", "content": "Hi"}],
                temperature=0.3,
                max_tokens=512,
            )

        body = mock.call_args[1]["json"]
        assert body["temperature"] == 0.3
        assert body["max_tokens"] == 512


class TestModelsClientEmbed:
    """Tests for models.embed()."""

    def test_embed_returns_embeddings(self, client):
        """embed() returns a parsed ModelEmbedding."""
        with patch.object(client, "_request", return_value=SAMPLE_MODEL_EMBEDDING):
            result = client.models.embed(texts=["Hello", "World"])

        assert isinstance(result, ModelEmbedding)
        assert len(result.embeddings) == 2
        assert result.model == "text-embedding-3-small"

    def test_embed_default_model(self, client):
        """embed() uses text-embedding-3-small by default."""
        with patch.object(client, "_request", return_value=SAMPLE_MODEL_EMBEDDING) as mock:
            client.models.embed(texts=["test"])

        body = mock.call_args[1]["json"]
        assert body["model"] == "text-embedding-3-small"


class TestModelsClientList:
    """Tests for models.list()."""

    def test_list_returns_model_info(self, client):
        """list() returns a list of ModelInfo objects."""
        with patch.object(client, "_request", return_value=SAMPLE_MODELS_LIST):
            result = client.models.list()

        assert isinstance(result, list)
        assert len(result) == 1
        assert isinstance(result[0], ModelInfo)
        assert result[0].name == "claude-sonnet-4"
        assert result[0].provider == "anthropic"
