"""Unit tests for build_args function.

This module contains basic tests for the build_args function.
"""

import pytest
from pydantic import ValidationError

from hezor_common.data_model.searching.data.api_models import (
    ParameterPropertySchema,
    ParameterSchema,
    SearchResponse,
    ToolSchema,
)
from hezor_common.transfer.datahub_sdk.build_args import (
    ParameterValidationError,
    ToolArgs,
    _check_param_type,
    _validate_args,
    build_args,
    build_args_for_all_tools,
)


@pytest.fixture
def sample_tool_schema():
    """Create a sample ToolSchema for testing."""
    param_schema = ParameterSchema(
        type="object",
        desc="Tool parameters",
        props={
            "city": ParameterPropertySchema(type="string", desc="City name"),
            "date": ParameterPropertySchema(type="string", desc="Date"),
            "temperature": ParameterPropertySchema(type="number", desc="Temperature"),
        },
        required=["city"],
    )

    return ToolSchema(
        name="get_weather",
        desc="Get weather information",
        params=param_schema,
        returns="Weather data",
    )


@pytest.fixture
def sample_tool_schema_2():
    """Create another sample ToolSchema for testing."""
    param_schema = ParameterSchema(
        type="object",
        desc="Forecast parameters",
        props={
            "location": ParameterPropertySchema(type="string", desc="Location"),
            "days": ParameterPropertySchema(type="integer", desc="Number of days"),
        },
        required=["location"],
    )

    return ToolSchema(
        name="get_forecast",
        desc="Get weather forecast",
        params=param_schema,
        returns="Forecast data",
    )


@pytest.fixture
def sample_search_response(sample_tool_schema):
    """Create a sample SearchResponse."""
    return SearchResponse(tools=[sample_tool_schema])


@pytest.fixture
def multi_tool_search_response(sample_tool_schema, sample_tool_schema_2):
    """Create a SearchResponse with multiple tools."""
    return SearchResponse(tools=[sample_tool_schema, sample_tool_schema_2])


@pytest.fixture
def empty_search_response():
    """Create an empty SearchResponse."""
    return SearchResponse(tools=[])


class TestBuildArgsBasic:
    """Basic tests for build_args function."""

    @pytest.mark.asyncio
    async def test_build_args_empty_response_raises_error(self, empty_search_response):
        """Test that build_args raises ValueError for empty search response."""
        with pytest.raises(ValueError, match="搜索结果为空"):
            await build_args(empty_search_response)

    @pytest.mark.asyncio
    async def test_build_args_with_tool_index(self, multi_tool_search_response):
        """Test that build_args can specify tool index."""
        # 测试索引范围检查
        with pytest.raises(IndexError, match="工具索引.*超出范围"):
            await build_args(multi_tool_search_response, tool_index=10)

    @pytest.mark.asyncio
    async def test_build_args_for_all_tools_empty_response(self, empty_search_response):
        """Test that build_args_for_all_tools raises ValueError for empty response."""
        with pytest.raises(ValueError, match="搜索结果为空"):
            await build_args_for_all_tools(empty_search_response)


class TestValidateArgs:
    """Tests for _validate_args function."""

    def test_validate_args_missing_required_param(self, sample_tool_schema):
        """Test that validation fails when required parameter is missing."""
        args = {"date": "2024-01-01"}  # Missing required 'city'

        with pytest.raises(ParameterValidationError, match="缺少必需参数"):
            _validate_args(args, sample_tool_schema)

    def test_validate_args_success(self, sample_tool_schema):
        """Test that validation passes with valid arguments."""
        args = {"city": "Beijing", "date": "2024-01-01"}

        # Should not raise
        _validate_args(args, sample_tool_schema)

    def test_validate_args_extra_param_warning(self, sample_tool_schema):
        """Test that extra parameters generate warning but don't fail."""
        args = {"city": "Beijing", "extra_param": "value"}

        # Should not raise
        _validate_args(args, sample_tool_schema)


class TestCheckParamType:
    """Tests for _check_param_type function."""

    def test_check_string_type_valid(self):
        """Test string type validation passes."""
        _check_param_type("city", "Beijing", "string")

    def test_check_string_type_invalid(self):
        """Test string type validation fails with wrong type."""
        with pytest.raises(ParameterValidationError, match="类型错误"):
            _check_param_type("city", 123, "string")

    def test_check_number_type_valid(self):
        """Test number type accepts int and float."""
        _check_param_type("temperature", 25, "number")
        _check_param_type("temperature", 25.5, "number")

    def test_check_number_type_invalid(self):
        """Test number type validation fails with string."""
        with pytest.raises(ParameterValidationError, match="类型错误"):
            _check_param_type("temperature", "hot", "number")

    def test_check_integer_type_valid(self):
        """Test integer type validation passes."""
        _check_param_type("count", 10, "integer")

    def test_check_integer_type_invalid(self):
        """Test integer type validation fails with float."""
        with pytest.raises(ParameterValidationError, match="类型错误"):
            _check_param_type("count", 10.5, "integer")

    def test_check_boolean_type_valid(self):
        """Test boolean type validation passes."""
        _check_param_type("enabled", True, "boolean")

    def test_check_array_type_valid(self):
        """Test array type validation passes."""
        _check_param_type("items", [1, 2, 3], "array")

    def test_check_object_type_valid(self):
        """Test object type validation passes."""
        _check_param_type("config", {"key": "value"}, "object")


class TestToolArgs:
    """Tests for ToolArgs Pydantic model."""

    def test_tool_args_creation(self):
        """Test ToolArgs model creation."""
        args = ToolArgs(args={"city": "Beijing", "date": "2024-01-01"})
        assert args.args["city"] == "Beijing"
        assert args.args["date"] == "2024-01-01"

    def test_tool_args_validation(self):
        """Test ToolArgs requires args field."""
        with pytest.raises(ValidationError):
            ToolArgs(args=None)  # type: ignore  # Invalid args
