"""Tests for the LumoClient."""

import pytest
import requests
from unittest.mock import Mock, patch

from lumo_sdk import LumoClient, Message, MessageRole
from lumo_sdk.exceptions import (
    LumoAuthenticationError,
    LumoRateLimitError,
    LumoServerError,
    LumoAPIError,
)


class TestLumoClient:
    """Test cases for LumoClient."""

    def test_init_with_api_key(self):
        """Test client initialization with API key."""
        client = LumoClient(api_key="test-key")
        assert client.api_key == "test-key"
        assert client.base_url == "https://api.starlight-search.com"

    def test_init_without_api_key(self):
        """Test that initialization without API key raises error."""
        with pytest.raises(ValueError, match="API key is required"):
            LumoClient(api_key="")

    def test_init_with_custom_base_url(self):
        """Test client initialization with custom base URL."""
        client = LumoClient(api_key="test-key", base_url="https://custom-url.com")
        assert client.base_url == "https://custom-url.com"

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_success(self, mock_post):
        """Test successful task execution."""
        # Mock response
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "final_answer": "The weather is sunny.",
            "steps": [
                {
                    "tool_calls": [],
                    "llm_output": "The weather is sunny.",
                }
            ],
        }
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        response = client.run_task(
            task="What is the weather?",
            model="gpt-4.1-mini",
            base_url="https://api.openai.com/v1/chat/completions",
        )

        assert response.final_answer == "The weather is sunny."
        assert len(response.steps) == 1
        mock_post.assert_called_once()

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_with_tools(self, mock_post):
        """Test task execution with tools."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "final_answer": "Task completed.",
            "steps": [],
        }
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        response = client.run_task(
            task="Search for something",
            model="gpt-4.1-mini",
            base_url="https://api.openai.com/v1/chat/completions",
            tools=["ExaSearchTool", "VisitWebsite"],
        )

        assert response.final_answer == "Task completed."
        call_args = mock_post.call_args
        assert "ExaSearchTool" in call_args[1]["json"]["tools"]

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_with_history(self, mock_post):
        """Test task execution with conversation history."""
        mock_response = Mock()
        mock_response.status_code = 200
        mock_response.json.return_value = {
            "final_answer": "I remember you said hello!",
            "steps": [],
        }
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        history = [
            Message(role=MessageRole.USER, content="Hello!"),
            Message(role=MessageRole.ASSISTANT, content="Hi there!"),
        ]
        response = client.run_task(
            task="What did I say?",
            model="gpt-4.1-mini",
            base_url="https://api.openai.com/v1/chat/completions",
            history=history,
        )

        assert response.final_answer == "I remember you said hello!"
        call_args = mock_post.call_args
        assert len(call_args[1]["json"]["history"]) == 2

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_authentication_error(self, mock_post):
        """Test handling of authentication errors."""
        mock_response = Mock()
        mock_response.status_code = 401
        mock_response.json.return_value = {"message": "Invalid API key"}
        mock_response.text = ""
        mock_post.return_value = mock_response

        client = LumoClient(api_key="invalid-key")
        with pytest.raises(LumoAuthenticationError) as exc_info:
            client.run_task(
                task="Test",
                model="gpt-4.1-mini",
                base_url="https://api.openai.com/v1/chat/completions",
            )
        assert exc_info.value.status_code == 401

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_rate_limit_error(self, mock_post):
        """Test handling of rate limit errors."""
        mock_response = Mock()
        mock_response.status_code = 429
        mock_response.json.return_value = {"message": "Rate limit exceeded"}
        mock_response.text = ""
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        with pytest.raises(LumoRateLimitError) as exc_info:
            client.run_task(
                task="Test",
                model="gpt-4.1-mini",
                base_url="https://api.openai.com/v1/chat/completions",
            )
        assert exc_info.value.status_code == 429

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_server_error(self, mock_post):
        """Test handling of server errors."""
        mock_response = Mock()
        mock_response.status_code = 500
        mock_response.json.return_value = {"message": "Internal server error"}
        mock_response.text = ""
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        with pytest.raises(LumoServerError) as exc_info:
            client.run_task(
                task="Test",
                model="gpt-4.1-mini",
                base_url="https://api.openai.com/v1/chat/completions",
            )
        assert exc_info.value.status_code == 500

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_bad_request(self, mock_post):
        """Test handling of bad request errors."""
        mock_response = Mock()
        mock_response.status_code = 400
        mock_response.json.return_value = {"message": "Invalid request"}
        mock_response.text = ""
        mock_post.return_value = mock_response

        client = LumoClient(api_key="test-key")
        with pytest.raises(LumoAPIError) as exc_info:
            client.run_task(
                task="Test",
                model="gpt-4.1-mini",
                base_url="https://api.openai.com/v1/chat/completions",
            )
        assert exc_info.value.status_code == 400

    @patch("lumo_sdk.client.requests.Session.post")
    def test_run_task_request_exception(self, mock_post):
        """Test handling of request exceptions."""
        mock_post.side_effect = requests.exceptions.ConnectionError("Connection failed")

        client = LumoClient(api_key="test-key")
        with pytest.raises(LumoAPIError) as exc_info:
            client.run_task(
                task="Test",
                model="gpt-4.1-mini",
                base_url="https://api.openai.com/v1/chat/completions",
            )
        assert "Request failed" in str(exc_info.value)

