"""Claude Agent 模块 - 自然语言理解和输出总结。"""

import asyncio
import os
import time
from typing import Any

import anthropic

from butler.config import settings


def _extract_text(content: list[Any]) -> str:
    """从响应内容中提取文本，跳过 ThinkingBlock 等。"""
    texts = []
    for block in content:
        if hasattr(block, "text"):
            texts.append(block.text)
    return "\n".join(texts).strip()


class ShellAgent:
    """基于 LLM 的 Shell 助手 Agent。"""

    UNDERSTAND_PROMPT = """你是一个远程服务器的 Shell 助手。用户通过自然语言描述他们想做的事情，你需要：

1. 理解用户的意图
2. 生成合适的 shell 命令
3. 只返回命令本身，不要解释

规则：
- 用户可能说"查看文件"、"列出目录"、"看下内存"等自然语言
- 你需要将其转换为准确的 shell 命令
- 如果用户输入已经是有效的 shell 命令，直接返回
- 如果无法理解，返回 "UNKNOWN: <原因>"
- 只返回一行命令，不要有多余内容

示例：
用户: "查看当前目录"
返回: ls -la

用户: "看下磁盘空间"
返回: df -h

用户: "查看最近的日志"
返回: tail -100 /var/log/syslog

用户: "ls -la"
返回: ls -la

用户: "我想编辑 config.yaml"
返回: vim config.yaml"""

    SUMMARIZE_PROMPT = """你是一个远程服务器的 Shell 助手。用户执行了一个命令，你需要用简洁的中文总结输出结果。

要求：
- 用自然语言总结，不要直接复制输出
- 突出关键信息：数量、状态、异常、路径等
- 如果有错误，明确指出错误原因
- 如果输出为空或只是提示符，说明命令执行完毕
- 保持简洁，1-3句话"""

    def __init__(
        self,
        api_key: str | None = None,
        base_url: str | None = None,
        model: str | None = None,
    ):
        self.api_key = api_key or settings.anthropic_api_key or os.environ.get("ANTHROPIC_API_KEY", "")
        self.base_url = base_url or settings.anthropic_base_url or os.environ.get("ANTHROPIC_BASE_URL", "")
        self.model = model or settings.anthropic_model or "claude-sonnet-4-20250514"
        self._client: anthropic.Anthropic | None = None
        self._last_call_time: float = 0
        self._min_interval: float = 2.0  # API 调用最小间隔（秒）

    @property
    def client(self) -> anthropic.Anthropic:
        """延迟初始化客户端。"""
        if self._client is None:
            if not self.api_key:
                raise ValueError("ANTHROPIC_API_KEY 未设置")
            kwargs: dict[str, Any] = {"api_key": self.api_key}
            if self.base_url:
                kwargs["base_url"] = self.base_url
            self._client = anthropic.Anthropic(**kwargs)
        return self._client

    def is_available(self) -> bool:
        """检查 API 是否可用。"""
        return bool(self.api_key)

    async def _rate_limit(self) -> None:
        """简单的速率限制，避免 429。"""
        now = time.monotonic()
        elapsed = now - self._last_call_time
        if elapsed < self._min_interval:
            await asyncio.sleep(self._min_interval - elapsed)
        self._last_call_time = time.monotonic()

    async def _call_api(
        self,
        system: str,
        user_message: str,
        max_tokens: int = 1024,
        messages: list[dict] | None = None,
    ) -> str | None:
        """调用 API，带重试和限流。"""
        await self._rate_limit()

        if messages is None:
            messages = [{"role": "user", "content": user_message}]
        else:
            messages = messages + [{"role": "user", "content": user_message}]

        try:
            response = self.client.messages.create(
                model=self.model,
                max_tokens=max_tokens,
                system=system,
                messages=messages,
            )
            return _extract_text(response.content)
        except anthropic.RateLimitError:
            print("[agent] Rate limited, waiting 5s...")
            await asyncio.sleep(5)
            try:
                response = self.client.messages.create(
                    model=self.model,
                    max_tokens=max_tokens,
                    system=system,
                    messages=messages,
                )
                return _extract_text(response.content)
            except Exception as e:
                print(f"[agent] Retry failed: {e}")
                return None
        except Exception as e:
            print(f"[agent] API error: {e}")
            return None

    async def understand(
        self,
        user_input: str,
        context: dict[str, Any] | None = None,
        llm_messages: list[dict] | None = None,
    ) -> str:
        """理解用户自然语言输入，生成 shell 命令。"""
        context_hint = ""
        if context:
            if context.get("pwd"):
                context_hint += f"\n当前目录: {context['pwd']}"
            if context.get("last_output"):
                context_hint += f"\n最近输出: {context['last_output'][:200]}"

        user_message = user_input
        if context_hint:
            user_message = f"{context_hint}\n\n用户: {user_input}"

        result = await self._call_api(
            self.UNDERSTAND_PROMPT,
            user_message,
            messages=llm_messages,
        )

        if result is None:
            return user_input

        if result.startswith("UNKNOWN:"):
            return user_input

        return result

    async def summarize(
        self,
        user_input: str,
        command: str,
        raw_output: str,
        llm_messages: list[dict] | None = None,
    ) -> str:
        """总结命令执行结果，返回自然语言回复。"""
        if not self.is_available():
            return f"执行了: {command}\n{raw_output[-500:]}"

        user_message = f"用户想: {user_input}\n执行的命令: {command}\n\n输出:\n{raw_output[:3000]}"
        result = await self._call_api(
            self.SUMMARIZE_PROMPT,
            user_message,
            max_tokens=2048,
            messages=llm_messages,
        )

        if result is None:
            return f"执行了: {command}\n{raw_output[-500:]}"

        return result


# 全局实例
agent = ShellAgent()
