"""Unit tests for execute_tool functions.

This module contains tests for execute_tool and execute_tool_from_json functions.
"""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from hezor_common.data_model.searching.data.api_models import ExecuteResponse
from hezor_common.transfer.base_sdk import MetaInfo
from hezor_common.transfer.datahub_sdk.execute_tool import (
    execute_tool,
    execute_tool_from_json,
)


@pytest.fixture
def mock_meta_info():
    """Create a mock MetaInfo object."""
    return MetaInfo(
        subject="测试主体",
        subject_code="test_001",
        caller_id="user_123",
        data_coverage="202401-202412",
        creation_slug="test_model",
        creation_name="测试模型",
    )


@pytest.fixture
def sample_execute_response():
    """Create a sample ExecuteResponse."""
    return ExecuteResponse(
        success=True,
        data={"temperature": 25, "condition": "sunny"},
        count=1,
    )


class TestExecuteTool:
    """Tests for execute_tool function."""

    @pytest.mark.asyncio
    async def test_execute_tool_basic(self, sample_execute_response):
        """Test basic tool execution."""
        with patch(
            "hezor_common.transfer.datahub_sdk.execute_tool.DataAPIClient"
        ) as mock_client_class:
            mock_client = MagicMock()
            mock_client.__aenter__ = AsyncMock(return_value=mock_client)
            mock_client.__aexit__ = AsyncMock(return_value=None)
            mock_client.execute_tool = AsyncMock(return_value=sample_execute_response)
            mock_client_class.return_value = mock_client

            result = await execute_tool(
                "get_weather",
                {"city": "Beijing"},
            )

            assert isinstance(result, ExecuteResponse)
            assert result.success is True
            assert result.data["temperature"] == 25  # type: ignore[index]

            mock_client.execute_tool.assert_called_once_with("get_weather", {"city": "Beijing"})

    @pytest.mark.asyncio
    async def test_execute_tool_with_auth(self, sample_execute_response, mock_meta_info):
        """Test execute_tool with authentication."""
        with patch(
            "hezor_common.transfer.datahub_sdk.execute_tool.DataAPIClient"
        ) as mock_client_class:
            mock_client = MagicMock()
            mock_client.__aenter__ = AsyncMock(return_value=mock_client)
            mock_client.__aexit__ = AsyncMock(return_value=None)
            mock_client.execute_tool = AsyncMock(return_value=sample_execute_response)
            mock_client_class.return_value = mock_client

            result = await execute_tool(
                "get_weather",
                {"city": "Beijing"},
                api_key="test_api_key",
                meta_info=mock_meta_info,
                private_key_path="/path/to/key",
                password=b"test_password",
                meta_info_expires_in=7200,
            )

            assert isinstance(result, ExecuteResponse)

            # Verify DataAPIClient was called with correct parameters
            mock_client_class.assert_called_once()
            call_kwargs = mock_client_class.call_args[1]
            assert call_kwargs["api_key"] == "test_api_key"
            assert call_kwargs["meta_info"] == mock_meta_info
            assert call_kwargs["private_key_path"] == "/path/to/key"
            assert call_kwargs["password"] == b"test_password"
            assert call_kwargs["meta_info_expires_in"] == 7200


class TestExecuteToolFromJson:
    """Tests for execute_tool_from_json function."""

    @pytest.mark.asyncio
    async def test_execute_tool_from_json_basic(self, sample_execute_response):
        """Test basic JSON tool execution."""
        with patch(
            "hezor_common.transfer.datahub_sdk.execute_tool.DataAPIClient"
        ) as mock_client_class:
            mock_client = MagicMock()
            mock_client.__aenter__ = AsyncMock(return_value=mock_client)
            mock_client.__aexit__ = AsyncMock(return_value=None)
            mock_client.execute_tool_from_json = AsyncMock(return_value=sample_execute_response)
            mock_client_class.return_value = mock_client

            json_request = '{"tool": "get_weather", "args": {"city": "Beijing"}}'
            result = await execute_tool_from_json(json_request)

            assert isinstance(result, ExecuteResponse)
            assert result.success is True

            mock_client.execute_tool_from_json.assert_called_once_with(json_request)

    @pytest.mark.asyncio
    async def test_execute_tool_from_json_with_auth(self, sample_execute_response, mock_meta_info):
        """Test execute_tool_from_json with authentication."""
        with patch(
            "hezor_common.transfer.datahub_sdk.execute_tool.DataAPIClient"
        ) as mock_client_class:
            mock_client = MagicMock()
            mock_client.__aenter__ = AsyncMock(return_value=mock_client)
            mock_client.__aexit__ = AsyncMock(return_value=None)
            mock_client.execute_tool_from_json = AsyncMock(return_value=sample_execute_response)
            mock_client_class.return_value = mock_client

            json_request = '{"tool": "get_weather", "args": {"city": "Beijing"}}'
            result = await execute_tool_from_json(
                json_request,
                api_key="test_api_key",
                meta_info=mock_meta_info,
                private_key_path="/path/to/key",
                password=b"test_password",
                meta_info_expires_in=7200,
            )

            assert isinstance(result, ExecuteResponse)

            # Verify DataAPIClient was called with correct parameters
            mock_client_class.assert_called_once()
            call_kwargs = mock_client_class.call_args[1]
            assert call_kwargs["api_key"] == "test_api_key"
            assert call_kwargs["meta_info"] == mock_meta_info
            assert call_kwargs["private_key_path"] == "/path/to/key"
            assert call_kwargs["password"] == b"test_password"
            assert call_kwargs["meta_info_expires_in"] == 7200


class TestIntegration:
    """Integration tests for execute_tool functions."""

    @pytest.mark.asyncio
    async def test_execute_tool_integration(self, sample_execute_response):
        """Test integration between execute_tool and DataAPIClient."""
        with patch(
            "hezor_common.transfer.datahub_sdk.execute_tool.DataAPIClient"
        ) as mock_client_class:
            mock_client = MagicMock()
            mock_client.__aenter__ = AsyncMock(return_value=mock_client)
            mock_client.__aexit__ = AsyncMock(return_value=None)
            mock_client.execute_tool = AsyncMock(return_value=sample_execute_response)
            mock_client_class.return_value = mock_client

            # Execute with complex args
            result = await execute_tool(
                "complex_tool",
                {
                    "param1": "value1",
                    "param2": 123,
                    "param3": {"nested": "value"},
                },
            )

            assert result.success is True
            mock_client.execute_tool.assert_called_once()
