"""Tests for the FastAPI server."""

import uuid
from unittest.mock import AsyncMock, patch

import pytest
from fastapi.testclient import TestClient

from sensei.types import QueryResult


@pytest.fixture
def client():
	"""Create a test client for the FastAPI app."""
	# Import after patches are set up
	from sensei.server.api import api_app

	return TestClient(api_app)


def test_health_endpoint(client):
	"""Test the health check endpoint."""
	response = client.get("/health")

	assert response.status_code == 200
	data = response.json()
	assert data["status"] == "healthy"


@pytest.mark.asyncio
async def test_query_endpoint_success(client):
	"""Test successful query endpoint."""
	with patch("sensei.server.api.core.handle_query", new_callable=AsyncMock) as mock_handle:
		mock_handle.return_value = QueryResult(
			query_id="11111111-1111-1111-1111-111111111111",
			markdown="# FastAPI Guide\n\nHere's how to use FastAPI...\n\n---\n**Help improve sensei:** Rate this response using `feedback` tool after trying it.\n\nQuery ID: `11111111-1111-1111-1111-111111111111`\n",
		)

		response = client.post(
			"/query",
			json={"query": "How do I use FastAPI?"},
		)

		assert response.status_code == 200
		data = response.json()

		# Verify response structure
		assert "query_id" in data
		assert "markdown" in data

		# Verify query_id is a valid UUID
		try:
			uuid.UUID(data["query_id"])
		except ValueError:
			pytest.fail("query_id is not a valid UUID")

		# Verify markdown contains response and feedback template
		assert "FastAPI Guide" in data["markdown"]
		assert "Help improve sensei" in data["markdown"]


@pytest.mark.asyncio
async def test_query_endpoint_empty_query(client):
	"""Test query endpoint with empty query."""
	response = client.post(
		"/query",
		json={"query": ""},
	)

	# Should fail validation due to min_length=1
	assert response.status_code == 422


@pytest.mark.asyncio
async def test_query_endpoint_missing_query(client):
	"""Test query endpoint with missing query field."""
	response = client.post(
		"/query",
		json={},
	)

	# Should fail validation due to required field
	assert response.status_code == 422


@pytest.mark.asyncio
async def test_query_endpoint_agent_error(client):
	"""Test query endpoint when agent raises an error."""
	from sensei.types import ToolError as SenseiToolError

	with patch("sensei.server.api.core.handle_query", new_callable=AsyncMock) as mock_handle:
		mock_handle.side_effect = SenseiToolError("Agent failed")

		response = client.post(
			"/query",
			json={"query": "test query"},
		)

		assert response.status_code == 500
		data = response.json()
		assert "detail" in data


@pytest.mark.asyncio
async def test_rate_endpoint_success(client):
	"""Test successful rating endpoint."""
	with patch("sensei.server.api.core.handle_rating", new_callable=AsyncMock) as mock_handle:
		response = client.post(
			"/rate",
			json={
				"query_id": "12345678-1234-5678-1234-567812345678",
				"correctness": 5,
				"relevance": 4,
				"usefulness": 5,
				"reasoning": "Worked in prod",
				"agent_model": "claude-3-5",
				"agent_system": "Claude Code",
				"agent_version": "2.0",
			},
		)

		assert response.status_code == 200
		data = response.json()
		assert data["status"] == "recorded"

		# Verify mock was called
		mock_handle.assert_called_once()


@pytest.mark.asyncio
async def test_rate_endpoint_without_feedback(client):
	"""Test rating endpoint without optional feedback."""
	with patch("sensei.server.api.core.handle_rating", new_callable=AsyncMock) as mock_handle:
		response = client.post(
			"/rate",
			json={
				"query_id": "22222222-2222-2222-2222-222222222222",
				"correctness": 3,
				"relevance": 3,
				"usefulness": 2,
			},
		)

		assert response.status_code == 200
		data = response.json()
		assert data["status"] == "recorded"

		# Verify mock was called
		mock_handle.assert_called_once()


@pytest.mark.asyncio
async def test_rate_endpoint_invalid_rating(client):
	"""Test rating endpoint with invalid rating value."""
	# Rating too low
	response = client.post(
		"/rate",
		json={
			"query_id": "test-query-789",
			"correctness": 0,
			"relevance": 3,
			"usefulness": 3,
		},
	)
	assert response.status_code == 422

	# Rating too high
	response = client.post(
		"/rate",
		json={
			"query_id": "test-query-789",
			"correctness": 6,
			"relevance": 3,
			"usefulness": 3,
		},
	)
	assert response.status_code == 422


@pytest.mark.asyncio
async def test_rate_endpoint_missing_fields(client):
	"""Test rating endpoint with missing required fields."""
	# Missing query_id
	response = client.post(
		"/rate",
		json={"correctness": 5, "relevance": 5, "usefulness": 5},
	)
	assert response.status_code == 422

	# Missing ratings
	response = client.post(
		"/rate",
		json={"query_id": "test-123"},
	)
	assert response.status_code == 422


def test_not_found_endpoint(client):
	"""Test 404 handler for non-existent endpoints."""
	response = client.get("/nonexistent")
	assert response.status_code == 404
	data = response.json()
	assert "detail" in data
