"""Tests for POST /v1/chat/completions (OpenAI-compatible endpoint)."""

from __future__ import annotations

from typing import TYPE_CHECKING

import pytest

if TYPE_CHECKING:
    from httpx import AsyncClient

# -------------------------------------------------------------------
# Error responses when no backends are available
# -------------------------------------------------------------------


@pytest.mark.unit
async def test_chat_no_backends_returns_error(client: AsyncClient) -> None:
    """Without any backends, a valid request should get a 503-class error."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "llama3.2:8b",
            "messages": [{"role": "user", "content": "Hello"}],
        },
    )
    # 503 BackendUnavailable is expected when no Ollama is running
    assert resp.status_code in (500, 502, 503)
    data = resp.json()
    assert "error" in data


@pytest.mark.unit
async def test_chat_error_is_openai_format(client: AsyncClient) -> None:
    """Error body should be wrapped in OpenAI's ``{"error": {...}}`` envelope."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "nonexistent-model",
            "messages": [{"role": "user", "content": "Hi"}],
        },
    )
    data = resp.json()
    assert "error" in data
    err = data["error"]
    assert "message" in err
    assert "type" in err


# -------------------------------------------------------------------
# Request validation
# -------------------------------------------------------------------


@pytest.mark.unit
async def test_chat_missing_model_returns_422(client: AsyncClient) -> None:
    """Omitting 'model' should be rejected by Pydantic validation."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "messages": [{"role": "user", "content": "Hello"}],
        },
    )
    assert resp.status_code == 422


@pytest.mark.unit
async def test_chat_missing_messages_returns_422(client: AsyncClient) -> None:
    """Omitting 'messages' should be rejected by Pydantic validation."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "llama3.2:8b",
        },
    )
    assert resp.status_code == 422


@pytest.mark.unit
async def test_chat_empty_messages_returns_400(client: AsyncClient) -> None:
    """Empty messages list should be rejected as invalid request."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "llama3.2:8b",
            "messages": [],
        },
    )
    # Route handler raises InvalidRequestError (400)
    assert resp.status_code == 400


@pytest.mark.unit
async def test_chat_invalid_json_returns_422(client: AsyncClient) -> None:
    """Non-JSON body should return 422."""
    resp = await client.post(
        "/v1/chat/completions",
        content=b"this is not json",
        headers={"content-type": "application/json"},
    )
    assert resp.status_code == 422


# -------------------------------------------------------------------
# Request format validation (for the schema)
# -------------------------------------------------------------------


@pytest.mark.unit
async def test_chat_accepts_stream_flag(client: AsyncClient) -> None:
    """Request with stream=true should be accepted (even if backend fails)."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "llama3.2:8b",
            "messages": [{"role": "user", "content": "Test"}],
            "stream": True,
        },
    )
    # Should either stream (200) or fail with backend error, not 422
    assert resp.status_code != 422


@pytest.mark.unit
async def test_chat_accepts_optional_params(client: AsyncClient) -> None:
    """Optional OpenAI params (temperature, max_tokens, etc.) should be accepted."""
    resp = await client.post(
        "/v1/chat/completions",
        json={
            "model": "llama3.2:8b",
            "messages": [{"role": "user", "content": "Test"}],
            "temperature": 0.7,
            "max_tokens": 100,
            "top_p": 0.9,
            "stop": ["\n"],
        },
    )
    # Should not fail on validation -- only backend unavailability
    assert resp.status_code != 422
