"""
OpenCode Bun 适配器 - 通过子进程调用 opencode 工具

这个适配器真正调用 opencode 的 TypeScript 实现，
而不是 Python 重新实现。

使用场景：
- 高级工具（LSP、CodeSearch 等）
- 需要完整功能（9 种编辑策略）
- 不在意性能开销（50-100ms per call）
"""

import json
import asyncio
import subprocess
from pathlib import Path
from typing import Any, Dict, Optional

from agent.tools.adapters.base import ToolAdapter
from agent.tools.models import ToolResult, ToolContext


class OpenCodeBunAdapter(ToolAdapter):
    """
    通过 Bun 子进程调用 opencode 工具

    需要安装 Bun: https://bun.sh/
    """

    def __init__(self):
        # wrapper 和 adapter 在同一目录
        self.wrapper_script = Path(__file__).parent / "opencode-wrapper.ts"
        self.opencode_path = Path(__file__).parent.parent.parent.parent / "vendor/opencode"

        # 检查 Bun 是否可用
        self._check_bun()

    def _check_bun(self):
        """检查 Bun 运行时是否可用"""
        try:
            result = subprocess.run(
                ["bun", "--version"],
                capture_output=True,
                timeout=5
            )
            if result.returncode != 0:
                raise RuntimeError("Bun is not available")
        except FileNotFoundError:
            raise RuntimeError(
                "Bun runtime not found. Install from https://bun.sh/\n"
                "Or use Python-based tools instead."
            )

    async def adapt_execute(
        self,
        tool_name: str,  # 'read', 'edit', 'bash' 等
        args: Dict[str, Any],
        context: Optional[ToolContext] = None
    ) -> ToolResult:
        """
        调用 opencode 工具

        Args:
            tool_name: opencode 工具名称
            args: 工具参数
            context: 上下文
        """
        # 构造命令
        cmd = [
            "bun", "run",
            str(self.wrapper_script),
            tool_name,
            json.dumps(args)
        ]

        # 执行
        try:
            process = await asyncio.create_subprocess_exec(
                *cmd,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                cwd=str(self.opencode_path)
            )

            stdout, stderr = await asyncio.wait_for(
                process.communicate(),
                timeout=30  # 30 秒超时
            )

            if process.returncode != 0:
                error_msg = stderr.decode('utf-8', errors='replace')
                return ToolResult(
                    title="OpenCode Error",
                    output=f"工具执行失败: {error_msg}",
                    error=error_msg
                )

            # 解析结果
            result_data = json.loads(stdout.decode('utf-8'))

            # 转换为 ToolResult
            return ToolResult(
                title=result_data.get("title", ""),
                output=result_data.get("output", ""),
                metadata=result_data.get("metadata", {}),
                long_term_memory=self.extract_memory(result_data)
            )

        except asyncio.TimeoutError:
            return ToolResult(
                title="Timeout",
                output="OpenCode 工具执行超时",
                error="Timeout after 30s"
            )
        except Exception as e:
            return ToolResult(
                title="Execution Error",
                output=f"调用 OpenCode 失败: {str(e)}",
                error=str(e)
            )

    def adapt_schema(self, original_schema: Dict) -> Dict:
        """OpenCode 使用 OpenAI 格式，直接返回"""
        return original_schema

    def extract_memory(self, result: Dict) -> str:
        """从 opencode 结果提取记忆"""
        metadata = result.get("metadata", {})

        if metadata.get("truncated"):
            return f"输出被截断 (file: {result.get('title', '')})"

        if "diagnostics" in metadata:
            count = len(metadata["diagnostics"])
            if count > 0:
                return f"检测到 {count} 个诊断问题"

        return ""
