"""LLM Adapter - 将现有 LLM 适配到 XBot 接口"""

import json
from dataclasses import dataclass, field
from typing import Any, Optional

from app.agent.llm.factory import LLMFactory


@dataclass
class ToolCallRequest:
    """A tool call request from the LLM."""
    id: str
    name: str
    arguments: dict[str, Any]

    def to_openai_tool_call(self) -> dict[str, Any]:
        return {
            "id": self.id,
            "type": "function",
            "function": {
                "name": self.name,
                "arguments": json.dumps(self.arguments, ensure_ascii=False),
            },
        }


@dataclass
class LLMResponse:
    """Response from an LLM provider."""
    content: str | None
    tool_calls: list[ToolCallRequest] = field(default_factory=list)
    finish_reason: str = "stop"
    usage: dict[str, int] = field(default_factory=dict)
    reasoning_content: str | None = None

    @property
    def has_tool_calls(self) -> bool:
        return len(self.tool_calls) > 0


class XBotLLMAdapter:
    """
    适配器：将现有 LLM 适配到 XBot 的 LLMProvider 接口

    封装 LLMFactory 创建的 LLM，使其符合 nanobot 风格的接口：
    - chat_with_retry(messages, tools, model) -> LLMResponse
    """

    def __init__(
        self,
        provider: str,
        model_name: str,
        api_key: Optional[str] = None,
        base_url: Optional[str] = None,
        temperature: float = 0.7,
        max_tokens: int = 4096,
    ):
        self.provider_name = provider
        self.model = model_name
        self.temperature = temperature
        self.max_tokens = max_tokens

        # 创建底层 LLM
        self._llm = LLMFactory.create(provider, model_name, api_key, base_url)

        # 检查是否支持 tool calling
        self._supports_tools = self._check_tool_support()

    def _check_tool_support(self) -> bool:
        """检查模型是否支持 tool calling"""
        # GPT-4, Claude 支持 tool calling
        # 简单的判断逻辑
        model_lower = self.model.lower()
        if "gpt-4" in model_lower or "claude" in model_lower:
            return True
        return True  # 默认支持

    async def chat_with_retry(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int | None = None,
        temperature: float | None = None,
    ) -> LLMResponse:
        """
        发送聊天请求（支持 tool calling）

        Args:
            messages: 消息列表
            tools: 工具定义列表
            model: 模型名称（可选）
            max_tokens: 最大 tokens（可选）
            temperature: 温度（可选）

        Returns:
            LLMResponse: 包含内容和/或工具调用
        """
        model = model or self.model
        max_tokens = max_tokens or self.max_tokens
        temperature = temperature or self.temperature

        try:
            # 使用流式调用来获取完整响应
            response = await self._llm.client.chat.completions.create(
                model=model,
                messages=messages,
                tools=tools,
                temperature=temperature,
                max_tokens=max_tokens,
            )

            message = response.choices[0].message

            # 检查是否有 tool calls
            if message.tool_calls and tools:
                tool_calls = []
                for tc in message.tool_calls:
                    tool_calls.append(ToolCallRequest(
                        id=tc.id,
                        name=tc.function.name,
                        arguments=json.loads(tc.function.arguments) if isinstance(tc.function.arguments, str) else tc.function.arguments,
                    ))

                return LLMResponse(
                    content=message.content,
                    tool_calls=tool_calls,
                    finish_reason="tool_calls",
                )
            else:
                return LLMResponse(
                    content=message.content or "",
                    finish_reason="stop",
                )

        except Exception as e:
            return LLMResponse(
                content=f"Error calling LLM: {str(e)}",
                finish_reason="error",
            )

    async def chat(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
    ) -> LLMResponse:
        """简化的 chat 方法"""
        return await self.chat_with_retry(
            messages=messages,
            tools=tools,
            model=model,
            max_tokens=max_tokens,
            temperature=temperature,
        )

    async def chat_stream(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]] | None = None,
        model: str | None = None,
        max_tokens: int = 4096,
        temperature: float = 0.7,
    ):
        """流式聊天"""
        model = model or self.model

        try:
            response = await self._llm.client.chat.completions.create(
                model=model,
                messages=messages,
                tools=tools,
                temperature=temperature,
                max_tokens=max_tokens,
                stream=True,
            )

            async for chunk in response:
                if chunk.choices[0].delta.content:
                    yield chunk.choices[0].delta.content

        except Exception as e:
            yield f"Error: {str(e)}"
