# coding=utf-8
"""
BuiltinTool 执行器。

内置工具的执行逻辑：
- 内部直接调用注册表中的处理函数，无需流式
- 外部流式接口需要封装流式事件（RunLifecycle, ContentAgentResult 等）
- 支持同步和异步执行
"""

from __future__ import annotations

import time
import uuid
from typing import AsyncIterator, Iterator

from loguru import logger

from turbo_agent_core.schema.enums import JSON
from turbo_agent_core.schema.events import (
    BaseEvent,
    RunLifecycleCreatedEvent,
    RunLifecycleCreatedPayload,
    RunLifecycleCompletedEvent,
    RunLifecycleCompletedPayload,
    RunLifecycleFailedEvent,
    RunLifecycleFailedPayload,
    ContentAgentResultStartEvent,
    ContentAgentResultStartPayload,
    ContentAgentResultEndEvent,
    ContentAgentResultEndPayload,
    ExecutorMetadata,
    UserInfo,
)
from turbo_agent_core.schema.agents import BuiltinTool
from turbo_agent_core.schema.utils.tools import get_builtin_tool_registry
from turbo_agent_runtime.utils.executor_identity import build_executor_id


class BuiltinToolRuntime(BuiltinTool):
    """内置工具运行时：执行已注册的 Python 函数。
    
    执行特点：
    - 内部直接调用函数，无流式处理
    - 外部流式接口封装完整的生命周期事件
    - 支持同步和异步执行
    """

    def _resolve_user_metadata(self, **kwargs) -> UserInfo:
        """解析用户信息。"""
        raw = kwargs.get("user_metadata") or kwargs.get("user_info")
        if isinstance(raw, UserInfo):
            return raw
        if isinstance(raw, dict):
            try:
                return UserInfo.model_validate(raw)
            except Exception:
                pass
        user_id = kwargs.get("user_id")
        username = kwargs.get("username")
        return UserInfo(id=str(user_id or "local"), username=str(username or "local"))

    def run(self, input: JSON, **kwargs) -> JSON:
        """同步执行内置工具。
        
        直接从注册表查找并执行对应的处理函数。
        """
        try:
            # 验证输入
            data = input if isinstance(input, dict) else {"value": input}
            valid_input = self.validate_input(data)
            
            # 获取注册表并执行
            registry = get_builtin_tool_registry()
            result = registry.execute(self.builtin_name, valid_input, tool=self, **kwargs)
            
            # 验证输出
            shaped = self.validate_output(result)
            
            return {
                "tool_id": self.id,
                "version_id": getattr(self, "version_id", None),
                "output": shaped,
                "raw": result,
            }
        except Exception as e:
            logger.exception(f"BuiltinTool 同步执行失败: {e}")
            return {"error": str(e), "tool_id": self.id}

    async def a_run(self, input: JSON, **kwargs) -> JSON:
        """异步执行内置工具。
        
        使用注册表的异步执行接口。
        """
        try:
            # 验证输入
            data = input if isinstance(input, dict) else {"value": input}
            valid_input = self.validate_input(data)
            
            # 获取注册表并异步执行
            registry = get_builtin_tool_registry()
            result = await registry.aexecute(self.builtin_name, valid_input, tool=self, **kwargs)
            
            # 验证输出
            shaped = self.validate_output(result)
            
            return {
                "tool_id": self.id,
                "version_id": getattr(self, "version_id", None),
                "output": shaped,
                "raw": result,
            }
        except Exception as e:
            logger.exception(f"BuiltinTool 异步执行失败: {e}")
            return {"error": str(e), "tool_id": self.id}

    def stream(self, input: JSON, **kwargs) -> Iterator[BaseEvent]:
        """同步流式执行（外部流式封装）。
        
        内部实际同步执行，外部包装为流式事件序列。
        """
        trace_id = str(uuid.uuid4())
        run_id = f"run_{self.id}_{int(time.time() * 1000)}"
        executor_type = self.run_type
        executor_id = build_executor_id(self, executor_type)
        executor_path = [executor_id]

        # 发送生命周期开始事件
        yield RunLifecycleCreatedEvent(
            trace_id=trace_id,
            trace_path=[],
            run_id=run_id,
            run_path=[run_id],
            executor_id=executor_id,
            executor_type=executor_type,
            executor_path=executor_path,
            executor_metadata=ExecutorMetadata(
                id=self.id,
                name=self.name,
                belong_to_project_path=self.belong_to_project_path,
                name_id=self.name_id,
                description=self.description,
                avatar_uri=self.avatar_uri,
                run_type=self.run_type,
                version_id=self.version_id,
                version=self.version_tag,
            ),
            user_metadata=self._resolve_user_metadata(**kwargs),
            payload=RunLifecycleCreatedPayload(input_data=input),
        )

        try:
            # 发送结果开始事件
            yield ContentAgentResultStartEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_type=executor_type,
                executor_path=executor_path,
                payload=ContentAgentResultStartPayload(mode="json"),
            )

            # 执行工具
            result = self.run(input, **kwargs)

            if "error" in result:
                # 错误处理
                yield ContentAgentResultEndEvent(
                    trace_id=trace_id,
                    run_id=run_id,
                    executor_id=executor_id,
                    executor_path=executor_path,
                    executor_type=executor_type,
                    payload=ContentAgentResultEndPayload(
                        status="error",
                        full_result=result,
                    ),
                )
                yield RunLifecycleFailedEvent(
                    trace_id=trace_id,
                    trace_path=[],
                    run_id=run_id,
                    run_path=[run_id],
                    executor_id=executor_id,
                    executor_path=executor_path,
                    executor_type=executor_type,
                    payload=RunLifecycleFailedPayload(
                        error={"code": "RuntimeError", "message": result["error"]}
                    ),
                )
                return

            # 成功处理
            output = result.get("output")
            yield ContentAgentResultEndEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=ContentAgentResultEndPayload(
                    status="success",
                    full_result=output,
                ),
            )

            yield RunLifecycleCompletedEvent(
                trace_id=trace_id,
                trace_path=[],
                run_id=run_id,
                run_path=[run_id],
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=RunLifecycleCompletedPayload(
                    output=output,
                    usage={"total_tokens": 0},
                ),
            )

        except Exception as e:
            logger.exception(f"BuiltinTool 流式执行失败: {e}")
            yield ContentAgentResultEndEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=ContentAgentResultEndPayload(
                    status="error",
                    full_result=str(e),
                ),
            )
            yield RunLifecycleFailedEvent(
                trace_id=trace_id,
                trace_path=[],
                run_id=run_id,
                run_path=[run_id],
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=RunLifecycleFailedPayload(
                    error={"code": "RuntimeError", "message": str(e)}
                ),
            )

    async def a_stream(self, input: JSON, **kwargs) -> AsyncIterator[BaseEvent]:
        """异步流式执行（外部流式封装）。
        
        内部实际异步执行，外部包装为流式事件序列。
        """
        trace_id = str(uuid.uuid4())
        run_id = f"run_{self.id}_{int(time.time() * 1000)}"
        executor_type = self.run_type
        executor_id = build_executor_id(self, executor_type)
        executor_path = [executor_id]

        # 发送生命周期开始事件
        yield RunLifecycleCreatedEvent(
            trace_id=trace_id,
            trace_path=[],
            run_id=run_id,
            run_path=[run_id],
            executor_id=executor_id,
            executor_type=executor_type,
            executor_path=executor_path,
            executor_metadata=ExecutorMetadata(
                id=self.id,
                name=self.name,
                belong_to_project_path=self.belong_to_project_path,
                name_id=self.name_id,
                description=self.description,
                avatar_uri=self.avatar_uri,
                run_type=self.run_type,
                version_id=self.version_id,
                version=self.version_tag,
            ),
            user_metadata=self._resolve_user_metadata(**kwargs),
            payload=RunLifecycleCreatedPayload(input_data=input),
        )

        try:
            # 发送结果开始事件
            yield ContentAgentResultStartEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_type=executor_type,
                executor_path=executor_path,
                payload=ContentAgentResultStartPayload(mode="json"),
            )

            # 异步执行工具
            result = await self.a_run(input, **kwargs)

            if "error" in result:
                # 错误处理
                yield ContentAgentResultEndEvent(
                    trace_id=trace_id,
                    run_id=run_id,
                    executor_id=executor_id,
                    executor_path=executor_path,
                    executor_type=executor_type,
                    payload=ContentAgentResultEndPayload(
                        status="error",
                        full_result=result,
                    ),
                )
                yield RunLifecycleFailedEvent(
                    trace_id=trace_id,
                    trace_path=[],
                    run_id=run_id,
                    run_path=[run_id],
                    executor_id=executor_id,
                    executor_path=executor_path,
                    executor_type=executor_type,
                    payload=RunLifecycleFailedPayload(
                        error={"code": "RuntimeError", "message": result["error"]}
                    ),
                )
                return

            # 成功处理
            output = result.get("output")
            yield ContentAgentResultEndEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=ContentAgentResultEndPayload(
                    status="success",
                    full_result=output,
                ),
            )

            yield RunLifecycleCompletedEvent(
                trace_id=trace_id,
                trace_path=[],
                run_id=run_id,
                run_path=[run_id],
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=RunLifecycleCompletedPayload(
                    output=output,
                    usage={"total_tokens": 0},
                ),
            )

        except Exception as e:
            logger.exception(f"BuiltinTool 异步流式执行失败: {e}")
            yield ContentAgentResultEndEvent(
                trace_id=trace_id,
                run_id=run_id,
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=ContentAgentResultEndPayload(
                    status="error",
                    full_result=str(e),
                ),
            )
            yield RunLifecycleFailedEvent(
                trace_id=trace_id,
                trace_path=[],
                run_id=run_id,
                run_path=[run_id],
                executor_id=executor_id,
                executor_path=executor_path,
                executor_type=executor_type,
                payload=RunLifecycleFailedPayload(
                    error={"code": "RuntimeError", "message": str(e)}
                ),
            )
