#  coding=utf-8
#  本文档定义了 智能体（Agent）、角色（Character）和工具（Tool）数据模型，以支持 运行、迁移、存储等功能
from __future__ import annotations

from typing import AsyncIterator, Iterator, List, Optional, Set, Literal, Union

from pydantic import BaseModel, Field, ValidationError

from turbo_agent_core.schema.enums import JSON, RequestMethod, RunType, ModelType
from turbo_agent_core.schema.events import BaseEvent
from turbo_agent_core.schema.basic import ModelParameters, ModelInstance, TurboEntity, Parameter
from turbo_agent_core.schema.external import Platform, Secret, McpServerSpec, McpResourceDescriptor
from turbo_agent_core.schema.resources import BusinessSetting
from turbo_agent_core.schema.states import Conversation, Message

from turbo_agent_core.utils.schema_tool import json_schema_to_pydantic_model
from turbo_agent_core.utils.param_schema import parameters_to_json_schema



# ToolVersion 已移除，统一以 Tool 为可运行工具实体

# TODO 实现run方法
class Tool(TurboEntity):
    run_type: Literal[RunType.Tool] = Field(default=RunType.Tool, description="工具运行类型。")
    # 版本追溯字段（核心层保留追溯而不维护版本容器）
    version_id: Optional[str] = Field(default=None, description="当前工具版本 ID。")
    version_tag: Optional[str] = Field(default=None, description="当前工具版本标签。")
    prev_version_id: Optional[str] = Field(default=None, description="上一版本 ID。")
    is_default: Optional[bool] = Field(default=None, description="是否为默认版本。")
    refSet: Set[str] = Field(default_factory=set, description="该工具依赖的实体 ID 集合。")
    async def a_run(self, input: JSON, **kwargs) -> JSON:
        raise NotImplementedError()
    
    async def a_stream(self, input: JSON,**kwargs) -> AsyncIterator[BaseEvent]:
        # 初始化一个事件流
        raise NotImplementedError()

    
    def run(self, input: JSON,  **kwargs) -> JSON:
        raise NotImplementedError()
    
    def stream(self, input: JSON,  **kwargs) -> Iterator[BaseEvent]:
        raise NotImplementedError()
    

    # 原始参数声明列表（前端/配置层给出）
    input: List[Parameter] = Field(default_factory=list, description="工具输入参数定义列表。")
    output: List[Parameter] = Field(default_factory=list, description="工具输出参数定义列表。")
    # 自动派生或显式指定的 JSON Schema（若外部直接提供则不覆盖）
    input_schema: JSON = Field(default_factory=dict, description="工具输入 JSON Schema。")
    output_schema: JSON = Field(default_factory=dict, description="工具输出 JSON Schema。")

    # 动态构造的校验模型（不参与序列化）
    _input_model: type[BaseModel] | None = None
    _output_model: type[BaseModel] | None = None

    def __init__(self, **data):
        super().__init__(**data)
        self._build_models()

    def model_post_init(self, __context):  # pydantic v2 hook
        # 若未显式提供 schema，则由参数列表派生
        if not self.input_schema and self.input:
            self.input_schema = parameters_to_json_schema(self.input)
        if not self.output_schema and self.output:
            self.output_schema = parameters_to_json_schema(self.output)
        self._build_models()

    # -------- public validation methods --------
    def validate_input(self, data: dict) -> dict:
        if not isinstance(self.input_schema, dict) or not self.input_schema:
            return data
        if not isinstance(data, dict):
            raise ValueError("Input must be dict for schema validation")
        if self._input_model is None:
            self._build_models()
        try:
            obj = self._input_model.model_validate(data)  # type: ignore
        except ValidationError as e:
            raise ValueError(e.errors()) from e
        return obj.model_dump()

    def validate_output(self, raw: JSON) -> dict:
        if not isinstance(self.output_schema, dict) or not self.output_schema:
            return {"result": raw}
        if self._output_model is None:
            self._build_models()
        if isinstance(raw, dict):
            try:
                obj = self._output_model.model_validate(raw)  # type: ignore
                return obj.model_dump()
            except ValidationError:
                pass
        props = self.output_schema.get("properties", {}) or {}
        if not props:
            return {"result": raw}
        if len(props) == 1:
            sole = next(iter(props.keys()))
            return {sole: raw}
        shaped = {k: None for k in props.keys()}
        first = next(iter(props.keys()))
        shaped[first] = raw
        return shaped

    # -------- internal helpers --------
    def _build_models(self):
        self._input_model = json_schema_to_pydantic_model(self.input_schema, "ToolInputModel") if isinstance(self.input_schema, dict) and self.input_schema else None
        self._output_model = json_schema_to_pydantic_model(self.output_schema, "ToolOutputModel") if isinstance(self.output_schema, dict) and self.output_schema else None


class LLMModel(TurboEntity):
    model_config = {'protected_namespaces': ()}
    series_name: str = Field(description="模型系列英文名。")
    source_urls: List[str] = Field(description="模型来源地址列表。")
    defaultParameters: ModelParameters = Field(default_factory=ModelParameters, description="模型默认参数配置。")
    run_type: Literal[RunType.LLM] = Field(default=RunType.LLM, description="实体运行类型，固定为大模型。")
    tool_calling_enabled: bool = Field(default=False, description="是否启用工具调用能力。")
    thinking_model:bool = Field(default=False, description="是否为支持思考链/推理模式的模型。")
    model_type: ModelType = Field(default=ModelType.LargeLanguageModel, description="模型类型。")
    instances: List[ModelInstance] = Field(default_factory=list, description="该模型可用的实例列表。")
    async def a_run(self, conversation: Conversation,leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Message:
        raise NotImplementedError()
    
    async def a_stream(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> AsyncIterator[BaseEvent]:
        # 初始化一个事件流
        raise NotImplementedError()

    
    def run(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Message:
        return super().run(**kwargs)
    
    def stream(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Iterator[BaseEvent]:
        raise NotImplementedError()


class BasicAgent(TurboEntity):
    run_type: Literal[RunType.AGENT] = Field(default=RunType.AGENT, description="实体运行类型，固定为智能体。")
    model: Optional[LLMModel] = Field(default=None, description="智能体绑定的大模型。")
    modelParameter: ModelParameters = Field(default_factory=ModelParameters, description="智能体运行时模型参数。")
    setting: Optional[BusinessSetting] = Field(default=None, description="智能体业务设置。")
    tools: List[Union["LLMTool", "APITool", "AgentTool", "FrontendTool", "BuiltinTool", "MCPTool", Tool]] = Field(default_factory=list, description="智能体可调用工具列表。")
    refSet: Set[str] = Field(default_factory=set, description="智能体依赖的实体 ID 集合。")
    # 版本追溯字段
    version_id: Optional[str] = Field(default=None, description="当前版本 ID。")
    version_tag: Optional[str] = Field(default=None, description="当前版本标签。")
    prev_version_id: Optional[str] = Field(default=None, description="上一版本 ID。")
    is_default: Optional[bool] = Field(default=None, description="是否为默认版本。")
    async def a_run(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Message:
        raise NotImplementedError()
    
    async def a_stream(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> AsyncIterator[BaseEvent]:
        # 初始化一个事件流
        raise NotImplementedError()

    
    def run(self, conversation: Conversation,  leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Message:
        return super().run(**kwargs)
    
    def stream(self, conversation: Conversation, leaf_message_id: Optional[str] = None, tools:Optional[List[Tool]] = None, **kwargs) -> Iterator[BaseEvent]:
        raise NotImplementedError()

# CharacterVersion 已移除，统一以 Character 为可运行角色实体
class Character(BasicAgent):
    run_type: Literal[RunType.Character] = Field(default=RunType.Character, description="实体运行类型，固定为角色。")
    expose_inner_thought: bool = Field(default=True, description="是否向外暴露角色的内部思考过程。")
    # 版本追溯字段
    version_id: Optional[str] = Field(default=None, description="当前角色版本 ID。")
    version_tag: Optional[str] = Field(default=None, description="当前角色版本标签。")
    prev_version_id: Optional[str] = Field(default=None, description="上一角色版本 ID。")
    is_default: Optional[bool] = Field(default=None, description="是否为默认角色版本。")

class Agent(BasicAgent):
    run_type: Literal[RunType.AGENT] = Field(default=RunType.AGENT, description="实体运行类型，固定为智能体。")
    hasMemory: bool = Field(default=False, description="是否启用长期记忆能力。")
    expose_inner_thought: bool = Field(default=True, description="是否向外暴露智能体的内部思考过程。")
    actAsCharacters: List[Character] = Field(default_factory=list, description="智能体可扮演的角色列表。")
    accountSecrets: List[Secret] = Field(default_factory=list, description="智能体可使用的账户凭据列表。")
    assistantAgents: List[Agent] = Field(default_factory=list, description="可作为辅助协作的子智能体列表。")
    refSet: Set[str] = Field(default_factory=set, description="智能体依赖的实体 ID 集合。")

# BasicTool 扩展，增加API工具相关字段,底层结构 refset为空
class APITool(Tool):
    method: RequestMethod = Field(default=RequestMethod.POST, description="API 请求方法。")
    needAccessSecret: Optional[bool] = Field(default=None, description="调用该工具时是否需要访问凭据。")
    platform: Platform = Field(description="该 API 工具所属的平台配置。")
    url_path_template: str = Field(description="API 路径模板。")

# BasicTool 扩展，作为一种特殊类型的智能体（大模型扮演工具）,底层结构 refset为空
class LLMTool(Tool):
    run_type: Literal[RunType.LLMTool] = Field(default=RunType.LLMTool, description="工具运行类型，固定为 LLMTool。")
    # 背靠大模型驱动的工具：具备类似 Agent 的配置，但遵循 Tool 的 I/O 契约
    model: Optional[LLMModel] = Field(default=None, description="该工具背靠的大模型。")
    modelParameter: ModelParameters = Field(default_factory=ModelParameters, description="该工具调用模型时使用的参数。")
    setting: Optional[BusinessSetting] = Field(default=None, description="该工具使用的业务设置。")

# BasicTool 扩展，使用特定智能体执行（智能体作为工具人）
class AgentTool(Tool):
    run_type: Literal[RunType.AgentTool] = Field(default=RunType.AgentTool, description="工具运行类型，固定为 AgentTool。")
    backendAgent: Optional[BasicAgent] = Field(default=None, description="实际执行该工具的后端智能体。")
    setting: Optional[BusinessSetting] = Field(default=None, description="该工具使用的业务设置。")
    refSet: Set[str] = Field(default_factory=set, description="该工具依赖的实体 ID 集合。")


# BasicTool 扩展，前端工具（运行时在特殊前端环境执行）
class FrontendTool(Tool):
    """前端工具：与 base Tool 结构一致，但类型为前端工具。
    
    前端工具的运行由 runtime 模块特殊处理，通常在浏览器/客户端环境中执行。
    核心层仅负责数据定义，运行逻辑由 runtime 实现。
    """
    run_type: Literal[RunType.Frontend] = Field(default=RunType.Frontend, description="工具运行类型，固定为前端工具。")
    platform: Optional[Platform] = Field(default=None, description="该前端工具关联的平台。")
    frontend_handler: Optional[str] = Field(default=None, description="前端侧执行处理器名称。")
    frontend_module: Optional[str] = Field(default=None, description="前端侧处理模块路径。")
    wait_strategy: Literal["poll_record", "push_callback"] = Field(default="poll_record", description="前端工具结果回传等待策略。")
    timeout_ms: Optional[int] = Field(default=None, description="前端工具执行超时时间，单位毫秒。")
    required_permissions: List[str] = Field(default_factory=list, description="执行该工具所需权限列表。")
    tags: List[str] = Field(default_factory=list, description="工具标签列表。")
    execution_hint: Optional[JSON] = Field(default=None, description="前端执行提示信息。")


# BasicTool 扩展，内置工具（代码层面注册，运行时直接调用）
class BuiltinTool(Tool):
    """内置工具：需要在代码层面注册的工具，由 Python 函数直接实现。
    
    builtin_name: 内置工具的唯一标识名，用于注册和查找
    handler_ref: 可选的处理器引用（运行时填充）
    """
    run_type: Literal[RunType.BUILTIN] = Field(default=RunType.BUILTIN, description="工具运行类型，固定为内置工具。")
    # 内置工具的名称标识，用于注册系统查找对应的处理函数
    builtin_name: str = Field(description="内置工具注册名。")
    platform: Optional[Platform] = Field(default=None, description="该内置工具关联的平台。")
    # 处理器模块路径（可选，用于动态加载）
    handler_module: Optional[str] = Field(default=None, description="处理函数所在模块路径。")
    required_permissions: List[str] = Field(default_factory=list, description="执行该内置工具所需权限列表。")
    tags: List[str] = Field(default_factory=list, description="内置工具标签列表。")
    execution_hint: Optional[JSON] = Field(default=None, description="执行提示信息。")


# BasicTool 扩展，MCP 工具（Model Context Protocol）
class MCPTool(Tool):
    """MCP 工具：基于 Model Context Protocol 的外部工具。
    
    MCP 工具通过 MCP 协议与外部服务通信，支持以下特性：
    - 连接到 MCP Server（stdio/http/ws 等传输方式）
    - 可选择是否需要平台授权
    - 支持平台级别的权限控制
    
    字段说明：
    - server: MCP 服务配置（传输方式、端点、启动参数等）
    - resource: MCP 资源描述（输入输出 schema 等）
    - require_platform_auth: 是否需要平台级授权
    - platform: 关联的平台（当需要平台授权时）
    """
    run_type: Literal[RunType.MCP] = Field(default=RunType.MCP, description="工具运行类型，固定为 MCP 工具。")
    
    # MCP 服务配置
    server: McpServerSpec = Field(description="MCP 服务配置。")
    
    # MCP 资源描述
    resource: McpResourceDescriptor = Field(description="MCP 资源描述。")
    
    # 是否需要平台授权（区分通用 MCP 和平台相关 MCP）
    require_platform_auth: bool = Field(default=False, description="是否需要平台级授权。")
    
    # 关联的平台（当 require_platform_auth=True 时有效）
    platform: Optional[Platform] = Field(default=None, description="当需要平台授权时关联的平台。")
    
    # 超时配置（毫秒），覆盖 server 中的默认配置
    timeout_ms: Optional[int] = Field(default=None, description="调用超时时间，单位毫秒。")


# Rebuild models to resolve forward references
BasicAgent.model_rebuild()
Character.model_rebuild()
Agent.model_rebuild()
MCPTool.model_rebuild()

