"""Data API 客户端。

用于与数据 API 网关进行交互，支持工具搜索和执行。
"""

import logging
from pathlib import Path
from typing import Any

import httpx

from hezor_common.data_model.searching.data.api_models import (
    ExecuteRequest,
    ExecuteResponse,
    SearchResponse,
)
from hezor_common.transfer.base_sdk import BaseAPIClient, MetaInfo
from hezor_common.transfer.datahub_sdk.base.constants import (
    DEFAULT_DATA_API_BASE_URL,
    DEFAULT_DATA_API_KEY,
)

logger = logging.getLogger(__name__)


class DataAPIClient(BaseAPIClient):
    """数据API客户端。

    用于与数据API网关进行交互，支持工具搜索和执行。
    继承自 BaseAPIClient，提供通用的认证和请求头管理功能。
    """

    def __init__(
        self,
        base_url: str = DEFAULT_DATA_API_BASE_URL,
        timeout: float = 120.0,
        api_key: str | None = DEFAULT_DATA_API_KEY,
        meta_info: MetaInfo | None = None,
        private_key_path: str | Path | None = None,
        password: bytes | None = None,
        meta_info_expires_in: int = 3600,
    ):
        """初始化客户端。

        Parameters
        ----------
        base_url : str
            API基础URL
        timeout : float
            请求超时时间（秒）
        api_key : str | None
            API密钥，用于Bearer token认证。如果为None，则不添加Authorization头
        meta_info : MetaInfo | None
            元信息对象，用于生成请求头。如果为None，则不添加元信息头
        private_key_path : str | Path | None
            私钥文件路径，用于JWT签名。如果为None且提供了meta_info，将使用匿名密钥
        password : bytes | None
            私钥密码，如果私钥加密则需要提供
        meta_info_expires_in : int
            MetaInfo JWT token过期时间（秒），默认3600秒
        """
        super().__init__(
            base_url=base_url,
            timeout=timeout,
            api_key=api_key,
            meta_info=meta_info,
            private_key_path=private_key_path,
            password=password,
            meta_info_expires_in=meta_info_expires_in,
        )

    async def search_tools(
        self,
        query: str,
        top_k: int = 3,
    ) -> SearchResponse:
        """搜索工具接口。

        根据语义搜索工具，返回匹配的工具定义。

        Parameters
        ----------
        query : str
            搜索查询字符串
        top_k : int
            返回的最大工具数量，默认为3

        Returns
        -------
        SearchResponse
            搜索响应，包含匹配的工具列表

        Raises
        ------
        httpx.HTTPError
            HTTP请求失败时抛出
        ValueError
            响应数据格式错误时抛出

        Examples
        --------
        >>> async with DataAPIClient() as client:
        ...     response = await client.search_tools("查询天气", top_k=5)
        ...     for tool in response.tools:
        ...         print(f"Tool: {tool.name} - {tool.desc}")
        """
        path = "/api/search"
        params = {"query": query, "top_k": top_k}

        logger.info(f"Searching tools with query: {query}, top_k: {top_k}")

        try:
            response = await self.get(path, params=params)
            response.raise_for_status()

            data = response.json()
            search_response = SearchResponse.model_validate(data)

            logger.info(f"Found {len(search_response.tools)} tools")
            return search_response

        except httpx.HTTPError as e:
            logger.error(f"HTTP error during tool search: {e}")
            raise
        except Exception as e:
            logger.error(f"Error parsing search response: {e}")
            raise ValueError(f"Invalid search response format: {e}") from e

    async def execute_tool(
        self,
        tool_name: str,
        args: dict[str, Any],
    ) -> ExecuteResponse:
        """执行工具接口。

        执行指定的工具并返回结果。

        Parameters
        ----------
        tool_name : str
            工具名称
        args : dict[str, Any]
            工具参数字典

        Returns
        -------
        ExecuteResponse
            执行响应，包含执行结果数据

        Raises
        ------
        httpx.HTTPError
            HTTP请求失败时抛出
        ValueError
            响应数据格式错误时抛出

        Examples
        --------
        >>> async with DataAPIClient() as client:
        ...     response = await client.execute_tool(
        ...         tool_name="get_weather",
        ...         args={"city": "北京", "date": "2025-12-18"}
        ...     )
        ...     print(f"Result: {response.data}")
        """
        path = "/api/execute"

        # 构造请求
        request = ExecuteRequest(tool=tool_name, args=args)

        logger.info(f"Executing tool: {tool_name} with args: {args}")

        try:
            response = await self.post(
                path,
                json=request.model_dump(),
            )
            response.raise_for_status()

            data = response.json()
            execute_response = ExecuteResponse.model_validate(data)

            logger.info(f"Tool execution completed: {tool_name}")
            return execute_response

        except httpx.HTTPError as e:
            logger.error(f"HTTP error during tool execution: {e}")
            raise
        except Exception as e:
            logger.error(f"Error parsing execution response: {e}")
            raise ValueError(f"Invalid execution response format: {e}") from e

    async def execute_tool_from_json(
        self,
        request_json: str,
    ) -> ExecuteResponse:
        """从JSON字符串执行工具接口。

        从JSON字符串构建ExecuteRequest并执行工具。

        Parameters
        ----------
        request_json : str
            JSON格式的执行请求字符串

        Returns
        -------
        ExecuteResponse
            执行响应，包含执行结果数据

        Raises
        ------
        httpx.HTTPError
            HTTP请求失败时抛出
        ValueError
            JSON格式错误或响应数据格式错误时抛出

        Examples
        --------
        >>> async with DataAPIClient() as client:
        ...     json_str = '{"tool": "get_weather", "args": {"city": "北京"}}'
        ...     response = await client.execute_tool_from_json(json_str)
        ...     print(f"Result: {response.data}")
        """
        path = "/api/execute"

        try:
            # 从JSON字符串构建请求
            request = ExecuteRequest.model_validate_json(request_json)
            logger.info(f"Executing tool from JSON: {request.tool}")

            response = await self.post(
                path,
                json=request.model_dump(),
            )
            response.raise_for_status()

            data = response.json()
            execute_response = ExecuteResponse.model_validate(data)

            logger.info(f"Tool execution completed: {request.tool}")
            return execute_response

        except httpx.HTTPError as e:
            logger.error(f"HTTP error during tool execution: {e}")
            raise
        except Exception as e:
            logger.error(f"Error parsing request or response: {e}")
            raise ValueError(f"Invalid JSON format or execution response: {e}") from e
